/* Duplicate a client certificate, which must be in the decrypted state. */ static ne_ssl_client_cert *dup_client_cert(const ne_ssl_client_cert *cc) { int ret; ne_ssl_client_cert *newcc = ne_calloc(sizeof *newcc); newcc->decrypted = 1; if (cc->keyless) { newcc->keyless = 1; } else { ret = gnutls_x509_privkey_init(&newcc->pkey); if (ret != 0) goto dup_error; ret = gnutls_x509_privkey_cpy(newcc->pkey, cc->pkey); if (ret != 0) goto dup_error; } newcc->cert.subject = x509_crt_copy(cc->cert.subject); if (!newcc->cert.subject) goto dup_error; if (cc->friendly_name) newcc->friendly_name = ne_strdup(cc->friendly_name); populate_cert(&newcc->cert, newcc->cert.subject); return newcc; dup_error: if (newcc->pkey) gnutls_x509_privkey_deinit(newcc->pkey); if (newcc->cert.subject) gnutls_x509_crt_deinit(newcc->cert.subject); ne_free(newcc); return NULL; }
int ne_ssl_clicert_decrypt(ne_ssl_client_cert *cc, const char *password) { int ret; gnutls_x509_crt cert = NULL; gnutls_x509_privkey pkey = NULL; if (gnutls_pkcs12_verify_mac(cc->p12, password) != 0) { return -1; } ret = pkcs12_parse(cc->p12, &pkey, &cert, NULL, password); if (ret < 0) return ret; if (!cert || (!pkey && !cc->keyless)) { if (cert) gnutls_x509_crt_deinit(cert); if (pkey) gnutls_x509_privkey_deinit(pkey); return -1; } gnutls_pkcs12_deinit(cc->p12); populate_cert(&cc->cert, cert); cc->pkey = pkey; cc->decrypted = 1; cc->p12 = NULL; return 0; }
ne_ssl_certificate *ne_ssl_cert_import(const char *data) { int ret; size_t len; unsigned char *der; gnutls_datum buffer = { NULL, 0 }; gnutls_x509_crt x5; if (gnutls_x509_crt_init(&x5) != 0) return NULL; /* decode the base64 to get the raw DER representation */ len = ne_unbase64(data, &der); if (len == 0) return NULL; buffer.data = der; buffer.size = len; ret = gnutls_x509_crt_import(x5, &buffer, GNUTLS_X509_FMT_DER); ne_free(der); if (ret < 0) { gnutls_x509_crt_deinit(x5); return NULL; } return populate_cert(ne_calloc(sizeof(struct ne_ssl_certificate_s)), x5); }
/* Return the certificate chain sent by the peer, or NULL on error. */ static ne_ssl_certificate *make_peers_chain(gnutls_session sock) { ne_ssl_certificate *current = NULL, *top = NULL; const gnutls_datum *certs; unsigned int n, count; certs = gnutls_certificate_get_peers(sock, &count); if (!certs) { return NULL; } for (n = 0; n < count; n++) { ne_ssl_certificate *cert; gnutls_x509_crt x5; if (gnutls_x509_crt_init(&x5) || gnutls_x509_crt_import(x5, &certs[n], GNUTLS_X509_FMT_DER)) { ne_ssl_cert_free(top); return NULL; } cert = populate_cert(ne_malloc(sizeof *cert), x5); if (top == NULL) { current = top = cert; } else { current->issuer = cert; current = cert; } } return top; }
ne_ssl_client_cert *ne_ssl_clicert_read(const char *filename) { int ret; gnutls_datum data; gnutls_pkcs12 p12; ne_ssl_client_cert *cc; char *friendly_name = NULL; gnutls_x509_crt cert = NULL; gnutls_x509_privkey pkey = NULL; if (read_to_datum(filename, &data)) return NULL; if (gnutls_pkcs12_init(&p12) != 0) { return NULL; } ret = gnutls_pkcs12_import(p12, &data, GNUTLS_X509_FMT_DER, 0); ne_free(data.data); if (ret < 0) { gnutls_pkcs12_deinit(p12); return NULL; } if (gnutls_pkcs12_verify_mac(p12, "") == 0) { if (pkcs12_parse(p12, &pkey, &cert, &friendly_name, "") != 0 || !cert || !pkey) { gnutls_pkcs12_deinit(p12); return NULL; } cc = ne_calloc(sizeof *cc); cc->pkey = pkey; cc->decrypted = 1; cc->friendly_name = friendly_name; populate_cert(&cc->cert, cert); gnutls_pkcs12_deinit(p12); cc->p12 = NULL; return cc; } else { /* TODO: calling pkcs12_parse() here to find the friendly_name * seems to break horribly. */ cc = ne_calloc(sizeof *cc); cc->p12 = p12; return cc; } }
ne_ssl_certificate *ne_ssl_cert_read(const char *filename) { int ret; gnutls_datum data; gnutls_x509_crt x5; if (read_to_datum(filename, &data)) return NULL; if (gnutls_x509_crt_init(&x5) != 0) return NULL; ret = gnutls_x509_crt_import(x5, &data, GNUTLS_X509_FMT_PEM); ne_free(data.data); if (ret < 0) { gnutls_x509_crt_deinit(x5); return NULL; } return populate_cert(ne_calloc(sizeof(struct ne_ssl_certificate_s)), x5); }
ne_ssl_client_cert *ne__ssl_clicert_exkey_import(const unsigned char *der, size_t der_len) { ne_ssl_client_cert *cc; gnutls_x509_crt x5; gnutls_datum datum; datum.data = (unsigned char *)der; datum.size = der_len; if (gnutls_x509_crt_init(&x5) || gnutls_x509_crt_import(x5, &datum, GNUTLS_X509_FMT_DER)) { NE_DEBUG(NE_DBG_SSL, "ssl: crt_import failed.\n"); return NULL; } cc = ne_calloc(sizeof *cc); cc->keyless = 1; cc->decrypted = 1; populate_cert(&cc->cert, x5); return cc; }
/* Return the certificate chain sent by the peer, or NULL on error. */ static ne_ssl_certificate *make_peers_chain(gnutls_session sock, gnutls_certificate_credentials crd) { ne_ssl_certificate *current = NULL, *top = NULL; const gnutls_datum *certs; unsigned int n, count; ne_ssl_certificate *cert; certs = gnutls_certificate_get_peers(sock, &count); if (!certs) { return NULL; } NE_DEBUG(NE_DBG_SSL, "ssl: Got %u certs in peer chain.\n", count); for (n = 0; n < count; n++) { gnutls_x509_crt x5; if (gnutls_x509_crt_init(&x5) || gnutls_x509_crt_import(x5, &certs[n], GNUTLS_X509_FMT_DER)) { if (top) { ne_ssl_cert_free(top); } return NULL; } cert = populate_cert(ne_calloc(sizeof *cert), x5); if (top == NULL) { current = top = cert; } else { current->issuer = cert; current = cert; } } #ifdef HAVE_GNUTLS_CERTIFICATE_GET_X509_CAS /* GnuTLS only returns the peers which were *sent* by the server * in the Certificate list during the handshake. Fill in the * complete chain manually against the certs we trust: */ if (current->issuer == NULL) { gnutls_x509_crt issuer; gnutls_x509_crt *ca_list; unsigned int num_cas; gnutls_certificate_get_x509_cas(crd, &ca_list, &num_cas); do { /* Look up the issuer. */ issuer = find_issuer(ca_list, num_cas, current->subject); if (issuer) { issuer = x509_crt_copy(issuer); cert = populate_cert(ne_calloc(sizeof *cert), issuer); /* Check that the issuer does not match the current * cert. */ if (ne_ssl_cert_cmp(current, cert)) { current = current->issuer = cert; } else { ne_ssl_cert_free(cert); issuer = NULL; } } } while (issuer); } #endif return top; }
ne_ssl_client_cert *SSL_X509_Pem_Read(const std::string & pkeyfile_str, const std::string & credfile_str, const std::string & password_str, DavixError** err){ FILE *fp; BIO* in=NULL; X509 *cert,*ca; STACK_OF(X509)* chain = NULL; EVP_PKEY *pkey; ne_ssl_client_cert *cc=NULL; int len, errcode; const char * pkeyfile = pkeyfile_str.c_str(), *credfile = credfile_str.c_str(), *password = password_str.c_str(); unsigned char* name; if( pkeyfile ==NULL || credfile ==NULL || ((in = BIO_new(BIO_s_file())) == NULL)){ DavixError::setupError(err, openssl_scope, StatusCode::UnknowError, "init error"); return NULL; } // load cred if (BIO_read_filename(in, credfile) <= 0){ std::ostringstream msg; msg << "impossible to open " << credfile << ": "; opensslErrorMapper(msg.str(), err); ERR_clear_error(); BIO_free(in); return NULL; } if ( (cert = PEM_read_bio_X509(in, NULL, SSL_pem_passwd_cb, (void*) password)) == NULL){ std::ostringstream msg; msg << "parse PEM credential failed " << credfile << ": "; opensslErrorMapper(msg.str(), err); ERR_clear_error(); BIO_free(in); return NULL; } // load chain chain = sk_X509_new_null(); while ((ca = PEM_read_bio_X509(in,NULL, SSL_pem_passwd_cb, (void*) password)) != NULL){ sk_X509_push(chain, ca); } /* When the while loop ends, it's usually just EOF. */ BIO_free(in); errcode = ERR_peek_last_error(); if (ERR_GET_LIB(errcode) == ERR_LIB_PEM && ERR_GET_REASON(errcode) == PEM_R_NO_START_LINE){ ERR_clear_error(); }else{ opensslErrorMapper(" parse PEM credential chain failed ", err); ERR_clear_error(); X509_free(cert); return NULL; } // load pkey fp = fopen(pkeyfile, "rb"); if (fp == NULL){ std::ostringstream ss; ss << "Impossible to open " << pkeyfile << " : " << strerror(errno); DavixError::setupError(err, openssl_scope, StatusCode::CredentialNotFound, ss.str()); errno = 0; X509_free(cert); return NULL; } if ( (pkey = PEM_read_PrivateKey(fp, NULL, SSL_pem_passwd_cb, (void*) password)) == NULL){ opensslErrorMapper(std::string("parse PEM private key failed ").append(pkeyfile), err); ERR_clear_error(); X509_free(cert); return NULL; } fclose(fp); // load ca chain name = X509_alias_get0(cert, &len); cc = (ne_ssl_client_cert*) calloc(sizeof(ne_ssl_client_cert),1); cc->pkey = pkey; cc->decrypted = 1; if (name && len > 0) cc->friendly_name = strndup((char *)name, len); populate_cert(&cc->cert, cert); cc->cert.chain = chain; return cc; }