From 980d0b6e67dce0088dcb49e6fa66bbb868f43000 Mon Sep 17 00:00:00 2001
From: Laszlo Kovacs <lkovacs@akamai.com>
Date: Wed, 25 Mar 2015 10:50:32 -0400
Subject: [PATCH 13/26] RT3868 Add SSL_get0_peer_certificate()

Add SSL_get0_peer_certificate() function which just returns the
pointer to the certificate; SSL_get_peer_certificate() increments
the references

(cherry picked from commit 10291475b39971cdac733011653af210c33fe992)

Conflicts:
	include/openssl/ssl.h
---
 doc/ssl/SSL_get_peer_certificate.pod | 18 ++++++++++++------
 include/openssl/ssl.h                |  1 +
 ssl/ssl_lib.c                        | 18 ++++++++++++++++++
 3 files changed, 31 insertions(+), 6 deletions(-)

diff --git a/doc/ssl/SSL_get_peer_certificate.pod b/doc/ssl/SSL_get_peer_certificate.pod
index ef7c8be..cbf27cb 100644
--- a/doc/ssl/SSL_get_peer_certificate.pod
+++ b/doc/ssl/SSL_get_peer_certificate.pod
@@ -2,18 +2,20 @@
 
 =head1 NAME
 
-SSL_get_peer_certificate - get the X509 certificate of the peer
+SSL_get_peer_certificate, SSL_get0_peer_certificate - get the X509 certificate of the peer
 
 =head1 SYNOPSIS
 
  #include <openssl/ssl.h>
 
  X509 *SSL_get_peer_certificate(const SSL *ssl);
+ X509 *SSL_get0_peer_certificate(const SSL *ssl);
 
 =head1 DESCRIPTION
 
-SSL_get_peer_certificate() returns a pointer to the X509 certificate the
-peer presented. If the peer did not present a certificate, NULL is returned.
+SSL_get_peer_certificate() and SSL_get0_peer_certificate() return a pointer 
+to the X509 certificate the peer presented. If the peer did not present a
+certificate, NULL is returned.
 
 =head1 NOTES
 
@@ -27,9 +29,13 @@ That a certificate is returned does not indicate information about the
 verification state, use L<SSL_get_verify_result(3)|SSL_get_verify_result(3)>
 to check the verification state.
 
-The reference count of the X509 object is incremented by one, so that it
-will not be destroyed when the session containing the peer certificate is
-freed. The X509 object must be explicitly freed using X509_free().
+The reference count of the X509 object returned by SSL_get_peer_certificate()
+is incremented by one, so that it will not be destroyed when the session
+containing the peer certificate is freed. The X509 object must be explicitly
+freed using X509_free().
+
+The reference count of the X509 object returned by SSL_get0_peer_certificate()
+is not incremented.
 
 =head1 RETURN VALUES
 
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 6fa3c4d..db46604 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -1551,6 +1551,7 @@ SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp,
 
 # ifdef HEADER_X509_H
 __owur X509 *SSL_get_peer_certificate(const SSL *s);
+__owur X509 *SSL_get0_peer_certificate(const SSL *s);
 # endif
 
 __owur STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *s);
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index e9dce65..74ee2a8 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -830,6 +830,24 @@ X509 *SSL_get_peer_certificate(const SSL *s)
     return (r);
 }
 
+/*
+ * Same as SSL_get_peer_certificate() except it doesn't
+ * increment the ref count of the returned X509*
+ */
+X509 *SSL_get0_peer_certificate(const SSL *s)
+{
+    X509 *r = SSL_get_peer_certificate(s);
+
+    /*
+     * the reference was just incremented, so decrement
+     * no need for X509_free() overhead
+     */
+    if (r)
+        CRYPTO_add(&r->references, -1, CRYPTO_LOCK_X509);
+
+    return (r);
+}
+
 STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *s)
 {
     STACK_OF(X509) *r;
-- 
2.3.2 (Apple Git-55)

