int pn_ssl_get_ssf(pn_ssl_t *ssl0) { const SSL_CIPHER *c; pni_ssl_t *ssl = get_ssl_internal(ssl0); if (ssl && ssl->ssl && (c = SSL_get_current_cipher( ssl->ssl ))) { return SSL_CIPHER_get_bits(c, NULL); } return 0; }
pn_ssl_resume_status_t pn_ssl_resume_status(pn_ssl_t *ssl0) { pni_ssl_t *ssl = get_ssl_internal(ssl0); if (!ssl || !ssl->ssl) return PN_SSL_RESUME_UNKNOWN; switch (SSL_session_reused( ssl->ssl )) { case 0: return PN_SSL_RESUME_NEW; case 1: return PN_SSL_RESUME_REUSED; default: break; } return PN_SSL_RESUME_UNKNOWN; }
bool pn_ssl_get_protocol_name(pn_ssl_t *ssl0, char *buffer, size_t size ) { const SSL_CIPHER *c; pni_ssl_t *ssl = get_ssl_internal(ssl0); *buffer = '\0'; if (ssl->ssl && (c = SSL_get_current_cipher( ssl->ssl ))) { const char *v = SSL_CIPHER_get_version(c); if (v) { snprintf( buffer, size, "%s", v ); return true; } } return false; }
const char* pn_ssl_get_remote_subject_subfield(pn_ssl_t *ssl0, pn_ssl_cert_subject_subfield field) { int openssl_field = 0; // Assign openssl internal representations of field values to openssl_field switch (field) { case PN_SSL_CERT_SUBJECT_COUNTRY_NAME : openssl_field = NID_countryName; break; case PN_SSL_CERT_SUBJECT_STATE_OR_PROVINCE : openssl_field = NID_stateOrProvinceName; break; case PN_SSL_CERT_SUBJECT_CITY_OR_LOCALITY : openssl_field = NID_localityName; break; case PN_SSL_CERT_SUBJECT_ORGANIZATION_NAME : openssl_field = NID_organizationName; break; case PN_SSL_CERT_SUBJECT_ORGANIZATION_UNIT : openssl_field = NID_organizationalUnitName; break; case PN_SSL_CERT_SUBJECT_COMMON_NAME : openssl_field = NID_commonName; break; default: ssl_log_error("Unknown or unhandled certificate subject subfield %i \n", field); return NULL; } pni_ssl_t *ssl = get_ssl_internal(ssl0); X509 *cert = get_peer_certificate(ssl); X509_NAME *subject_name = X509_get_subject_name(cert); // TODO (gmurthy) - A server side cert subject field can have more than one common name like this - Subject: CN=www.domain1.com, CN=www.domain2.com, see https://bugzilla.mozilla.org/show_bug.cgi?id=380656 // For now, we will only return the first common name if there is more than one common name in the cert int index = X509_NAME_get_index_by_NID(subject_name, openssl_field, -1); if (index > -1) { X509_NAME_ENTRY *ne = X509_NAME_get_entry(subject_name, index); if(ne) { ASN1_STRING *name_asn1 = X509_NAME_ENTRY_get_data(ne); return (char *) name_asn1->data; } } return NULL; }
int pn_ssl_get_peer_hostname(pn_ssl_t *ssl0, char *hostname, size_t *bufsize) { pni_ssl_t *ssl = get_ssl_internal(ssl0); if (!ssl) return -1; if (!ssl->peer_hostname) { *bufsize = 0; if (hostname) *hostname = '\0'; return 0; } unsigned len = strlen(ssl->peer_hostname); if (hostname) { if (len >= *bufsize) return -1; strcpy( hostname, ssl->peer_hostname ); } *bufsize = len; return 0; }
int pn_ssl_set_peer_hostname(pn_ssl_t *ssl0, const char *hostname) { pni_ssl_t *ssl = get_ssl_internal(ssl0); if (!ssl) return -1; if (ssl->peer_hostname) free((void *)ssl->peer_hostname); ssl->peer_hostname = NULL; if (hostname) { ssl->peer_hostname = pn_strdup(hostname); if (!ssl->peer_hostname) return -2; #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME if (ssl->ssl && ssl->domain && ssl->domain->mode == PN_SSL_MODE_CLIENT) { SSL_set_tlsext_host_name(ssl->ssl, ssl->peer_hostname); } #endif } return 0; }
const char* pn_ssl_get_remote_subject(pn_ssl_t *ssl0) { pni_ssl_t *ssl = get_ssl_internal(ssl0); if (!ssl || !ssl->ssl) return NULL; if (!ssl->subject) { X509 *cert = SSL_get_peer_certificate(ssl->ssl); if (!cert) return NULL; X509_NAME *subject = X509_get_subject_name(cert); if (!subject) return NULL; BIO *out = BIO_new(BIO_s_mem()); X509_NAME_print_ex(out, subject, 0, XN_FLAG_RFC2253); int len = BIO_number_written(out); ssl->subject = (char*) malloc(len+1); ssl->subject[len] = 0; BIO_read(out, ssl->subject, len); BIO_free(out); } return ssl->subject; }
int pn_ssl_get_cert_fingerprint(pn_ssl_t *ssl0, char *fingerprint, size_t fingerprint_length, pn_ssl_hash_alg hash_alg) { const char *digest_name = NULL; size_t min_required_length; // old versions of python expect fingerprint to contain a valid string on // return from this function fingerprint[0] = 0; // Assign the correct digest_name value based on the enum values. switch (hash_alg) { case PN_SSL_SHA1 : min_required_length = 41; // 40 hex characters + 1 '\0' character digest_name = "sha1"; break; case PN_SSL_SHA256 : min_required_length = 65; // 64 hex characters + 1 '\0' character digest_name = "sha256"; break; case PN_SSL_SHA512 : min_required_length = 129; // 128 hex characters + 1 '\0' character digest_name = "sha512"; break; case PN_SSL_MD5 : min_required_length = 33; // 32 hex characters + 1 '\0' character digest_name = "md5"; break; default: ssl_log_error("Unknown or unhandled hash algorithm %i \n", hash_alg); return PN_ERR; } if(fingerprint_length < min_required_length) { ssl_log_error("Insufficient fingerprint_length %i. fingerprint_length must be %i or above for %s digest\n", fingerprint_length, min_required_length, digest_name); return PN_ERR; } const EVP_MD *digest = EVP_get_digestbyname(digest_name); pni_ssl_t *ssl = get_ssl_internal(ssl0); X509 *cert = get_peer_certificate(ssl); if(cert) { unsigned int len; unsigned char bytes[64]; // sha512 uses 64 octets, we will use that as the maximum. if (X509_digest(cert, digest, bytes, &len) != 1) { ssl_log_error("Failed to extract X509 digest\n"); return PN_ERR; } char *cursor = fingerprint; for (size_t i=0; i<len ; i++) { cursor += snprintf((char *)cursor, fingerprint_length, "%02x", bytes[i]); fingerprint_length = fingerprint_length - 2; } return PN_OK; } else { ssl_log_error("No certificate is available yet \n"); return PN_ERR; } return 0; }