diff --git a/src/openssl/tls.c b/src/openssl/tls.c index 635ba5ee..18a5e970 100644 --- a/src/openssl/tls.c +++ b/src/openssl/tls.c @@ -48,6 +48,20 @@ # include "ssl_dane/danessl.h" #endif +static _getdns_tls_x509* _getdns_tls_x509_new(X509* cert) +{ + _getdns_tls_x509* res; + + if (!cert) + return NULL; + + res = malloc(sizeof(_getdns_tls_x509)); + if (res) + res->ssl = cert; + + return res; +} + #ifdef USE_WINSOCK /* For windows, the CA trust store is not read by openssl. Add code to open the trust store using wincrypt API and add @@ -374,6 +388,14 @@ getdns_return_t _getdns_tls_connection_do_handshake(_getdns_tls_connection* conn } } +_getdns_tls_x509* _getdns_tls_connection_get_peer_certificate(_getdns_tls_connection* conn) +{ + if (!conn || !conn->ssl) + return NULL; + + return _getdns_tls_x509_new(SSL_get_peer_certificate(conn->ssl)); +} + getdns_return_t _getdns_tls_connection_is_session_reused(_getdns_tls_connection* conn) { if (!conn || !conn->ssl) @@ -486,4 +508,19 @@ getdns_return_t _getdns_tls_get_api_information(getdns_dict* dict) return GETDNS_RETURN_GENERIC_ERROR; } +void _getdns_tls_x509_free(_getdns_tls_x509* cert) +{ + if (cert && cert->ssl) + X509_free(cert->ssl); + free(cert); +} + +int _getdns_tls_x509_to_der(_getdns_tls_x509* cert, uint8_t** buf) +{ + if (!cert || !cert->ssl) + return 0; + + return i2d_X509(cert->ssl, buf); +} + /* tls.c */ diff --git a/src/openssl/tls.h b/src/openssl/tls.h index 7e95a165..92e35459 100644 --- a/src/openssl/tls.h +++ b/src/openssl/tls.h @@ -64,6 +64,11 @@ typedef struct _getdns_tls_session { SSL_SESSION* ssl; } _getdns_tls_session; +typedef struct _getdns_tls_x509 +{ + X509* ssl; +} _getdns_tls_x509; + void _getdns_tls_init(); _getdns_tls_context* _getdns_tls_context_new(); @@ -103,6 +108,14 @@ const char* _getdns_tls_connection_get_version(_getdns_tls_connection* conn); */ getdns_return_t _getdns_tls_connection_do_handshake(_getdns_tls_connection* conn); +/** + * Get the connection peer certificate. + * + * @param conn the connection. + * @return certificate or NULL on error. + */ +_getdns_tls_x509* _getdns_tls_connection_get_peer_certificate(_getdns_tls_connection* conn); + /** * See whether the connection is reusing a session. * @@ -145,6 +158,22 @@ getdns_return_t _getdns_tls_connection_write(_getdns_tls_connection* conn, uint8 getdns_return_t _getdns_tls_session_free(_getdns_tls_session* s); +/** + * Free X509 certificate. + * + * @param cert the certificate. + */ +void _getdns_tls_x509_free(_getdns_tls_x509* cert); + +/** + * Convert X509 to DER. + * + * @param cert the certificate. + * @param buf buffer to receive conversion. NULL to just get the length. + * @return length of conversion, 0 on error. + */ +int _getdns_tls_x509_to_der(_getdns_tls_x509* cert, uint8_t** buf); + getdns_return_t _getdns_tls_get_api_information(getdns_dict* dict); #endif /* _GETDNS_TLS_H */ diff --git a/src/stub.c b/src/stub.c index fdcc9db6..d012566b 100644 --- a/src/stub.c +++ b/src/stub.c @@ -1797,7 +1797,7 @@ upstream_write_cb(void *userarg) getdns_upstream *upstream = (getdns_upstream *)userarg; getdns_network_req *netreq = upstream->write_queue; int q; - X509 *cert; + _getdns_tls_x509 *cert; if (!netreq) { GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event); @@ -1860,10 +1860,10 @@ upstream_write_cb(void *userarg) if (netreq->owner->return_call_reporting && netreq->upstream->tls_obj) { if (netreq->debug_tls_peer_cert.data == NULL && - (cert = SSL_get_peer_certificate(netreq->upstream->tls_obj->ssl))) { - netreq->debug_tls_peer_cert.size = i2d_X509( + (cert = _getdns_tls_connection_get_peer_certificate(netreq->upstream->tls_obj))) { + netreq->debug_tls_peer_cert.size = _getdns_tls_x509_to_der( cert, &netreq->debug_tls_peer_cert.data); - X509_free(cert); + _getdns_tls_x509_free(cert); } netreq->debug_tls_version = _getdns_tls_connection_get_version(netreq->upstream->tls_obj); }