int ssl_cert_type(X509 *x, EVP_PKEY *pkey) { EVP_PKEY *pk; int ret= -1,i; if (pkey == NULL) pk=X509_get_pubkey(x); else pk=pkey; if (pk == NULL) goto err; i=pk->type; if (i == EVP_PKEY_RSA) { ret=SSL_PKEY_RSA_ENC; } else if (i == EVP_PKEY_DSA) { ret=SSL_PKEY_DSA_SIGN; } #ifndef OPENSSL_NO_EC else if (i == EVP_PKEY_EC) { ret = SSL_PKEY_ECC; } #endif else if (i == NID_id_GostR3410_94 || i == NID_id_GostR3410_94_cc) { ret = SSL_PKEY_GOST94; } else if (i == NID_id_GostR3410_2001 || i == NID_id_GostR3410_2001_cc) { ret = SSL_PKEY_GOST01; } else if (x && (i == EVP_PKEY_DH || i == EVP_PKEY_DHX)) { /* For DH two cases: DH certificate signed with RSA and * DH certificate signed with DSA. */ i = X509_certificate_type(x, pk); if (i & EVP_PKS_RSA) ret = SSL_PKEY_DH_RSA; else if (i & EVP_PKS_DSA) ret = SSL_PKEY_DH_DSA; } err: if(!pkey) EVP_PKEY_free(pk); return(ret); }
/** * setup callback to allow the user to examine certificates which have * failed to validate during fetch. */ static void curl_start_cert_validate(struct curl_fetch_info *f, struct cert_info *certs) { int depth; BIO *mem; BUF_MEM *buf; struct ssl_cert_info ssl_certs[MAX_CERTS]; fetch_msg msg; for (depth = 0; depth <= f->cert_depth; depth++) { assert(certs[depth].cert != NULL); /* get certificate version */ ssl_certs[depth].version = X509_get_version(certs[depth].cert); /* not before date */ mem = BIO_new(BIO_s_mem()); ASN1_TIME_print(mem, X509_get_notBefore(certs[depth].cert)); BIO_get_mem_ptr(mem, &buf); (void) BIO_set_close(mem, BIO_NOCLOSE); BIO_free(mem); memcpy(ssl_certs[depth].not_before, buf->data, min(sizeof(ssl_certs[depth].not_before) - 1, (unsigned)buf->length)); ssl_certs[depth].not_before[min(sizeof(ssl_certs[depth].not_before) - 1, (unsigned)buf->length)] = 0; BUF_MEM_free(buf); /* not after date */ mem = BIO_new(BIO_s_mem()); ASN1_TIME_print(mem, X509_get_notAfter(certs[depth].cert)); BIO_get_mem_ptr(mem, &buf); (void) BIO_set_close(mem, BIO_NOCLOSE); BIO_free(mem); memcpy(ssl_certs[depth].not_after, buf->data, min(sizeof(ssl_certs[depth].not_after) - 1, (unsigned)buf->length)); ssl_certs[depth].not_after[min(sizeof(ssl_certs[depth].not_after) - 1, (unsigned)buf->length)] = 0; BUF_MEM_free(buf); /* signature type */ ssl_certs[depth].sig_type = X509_get_signature_type(certs[depth].cert); /* serial number */ ssl_certs[depth].serial = ASN1_INTEGER_get( X509_get_serialNumber(certs[depth].cert)); /* issuer name */ mem = BIO_new(BIO_s_mem()); X509_NAME_print_ex(mem, X509_get_issuer_name(certs[depth].cert), 0, XN_FLAG_SEP_CPLUS_SPC | XN_FLAG_DN_REV | XN_FLAG_FN_NONE); BIO_get_mem_ptr(mem, &buf); (void) BIO_set_close(mem, BIO_NOCLOSE); BIO_free(mem); memcpy(ssl_certs[depth].issuer, buf->data, min(sizeof(ssl_certs[depth].issuer) - 1, (unsigned) buf->length)); ssl_certs[depth].issuer[min(sizeof(ssl_certs[depth].issuer) - 1, (unsigned) buf->length)] = 0; BUF_MEM_free(buf); /* subject */ mem = BIO_new(BIO_s_mem()); X509_NAME_print_ex(mem, X509_get_subject_name(certs[depth].cert), 0, XN_FLAG_SEP_CPLUS_SPC | XN_FLAG_DN_REV | XN_FLAG_FN_NONE); BIO_get_mem_ptr(mem, &buf); (void) BIO_set_close(mem, BIO_NOCLOSE); BIO_free(mem); memcpy(ssl_certs[depth].subject, buf->data, min(sizeof(ssl_certs[depth].subject) - 1, (unsigned)buf->length)); ssl_certs[depth].subject[min(sizeof(ssl_certs[depth].subject) - 1, (unsigned) buf->length)] = 0; BUF_MEM_free(buf); /* type of certificate */ ssl_certs[depth].cert_type = X509_certificate_type(certs[depth].cert, X509_get_pubkey(certs[depth].cert)); /* and clean up */ certs[depth].cert->references--; if (certs[depth].cert->references == 0) { X509_free(certs[depth].cert); } } msg.type = FETCH_CERT_ERR; msg.data.cert_err.certs = ssl_certs; msg.data.cert_err.num_certs = depth; fetch_send_callback(&msg, f->fetch_handle); }
/** * Handle a completed fetch (CURLMSG_DONE from curl_multi_info_read()). * * \param curl_handle curl easy handle of fetch * \param result The result code of the completed fetch. */ static void fetch_curl_done(CURL *curl_handle, CURLcode result) { fetch_msg msg; bool finished = false; bool error = false; bool cert = false; bool abort_fetch; struct curl_fetch_info *f; char **_hideous_hack = (char **) (void *) &f; CURLcode code; struct cert_info certs[MAX_CERTS]; memset(certs, 0, sizeof(certs)); /* find the structure associated with this fetch */ /* For some reason, cURL thinks CURLINFO_PRIVATE should be a string?! */ code = curl_easy_getinfo(curl_handle, CURLINFO_PRIVATE, _hideous_hack); assert(code == CURLE_OK); abort_fetch = f->abort; LOG("done %s", nsurl_access(f->url)); if (abort_fetch == false && (result == CURLE_OK || (result == CURLE_WRITE_ERROR && f->stopped == false))) { /* fetch completed normally or the server fed us a junk gzip * stream (usually in the form of garbage at the end of the * stream). Curl will have fed us all but the last chunk of * decoded data, which is sad as, if we'd received the last * chunk, too, we'd be able to render the whole object. * As is, we'll just have to accept that the end of the * object will be truncated in this case and leave it to * the content handlers to cope. */ if (f->stopped || (!f->had_headers && fetch_curl_process_headers(f))) ; /* redirect with no body or similar */ else finished = true; } else if (result == CURLE_PARTIAL_FILE) { /* CURLE_PARTIAL_FILE occurs if the received body of a * response is smaller than that specified in the * Content-Length header. */ if (!f->had_headers && fetch_curl_process_headers(f)) ; /* redirect with partial body, or similar */ else { finished = true; } } else if (result == CURLE_WRITE_ERROR && f->stopped) { /* CURLE_WRITE_ERROR occurs when fetch_curl_data * returns 0, which we use to abort intentionally */ ; } else if (result == CURLE_SSL_PEER_CERTIFICATE || result == CURLE_SSL_CACERT) { memcpy(certs, f->cert_data, sizeof(certs)); memset(f->cert_data, 0, sizeof(f->cert_data)); cert = true; } else { LOG("Unknown cURL response code %d", result); error = true; } fetch_curl_stop(f); if (abort_fetch) ; /* fetch was aborted: no callback */ else if (finished) { msg.type = FETCH_FINISHED; fetch_send_callback(&msg, f->fetch_handle); } else if (cert) { int i; BIO *mem; BUF_MEM *buf; struct ssl_cert_info ssl_certs[MAX_CERTS]; for (i = 0; i < MAX_CERTS && certs[i].cert; i++) { ssl_certs[i].version = X509_get_version(certs[i].cert); mem = BIO_new(BIO_s_mem()); ASN1_TIME_print(mem, X509_get_notBefore(certs[i].cert)); BIO_get_mem_ptr(mem, &buf); (void) BIO_set_close(mem, BIO_NOCLOSE); BIO_free(mem); memcpy(ssl_certs[i].not_before, buf->data, min(sizeof(ssl_certs[i].not_before) - 1, (unsigned)buf->length)); ssl_certs[i].not_before[min(sizeof(ssl_certs[i].not_before) - 1, (unsigned)buf->length)] = 0; BUF_MEM_free(buf); mem = BIO_new(BIO_s_mem()); ASN1_TIME_print(mem, X509_get_notAfter(certs[i].cert)); BIO_get_mem_ptr(mem, &buf); (void) BIO_set_close(mem, BIO_NOCLOSE); BIO_free(mem); memcpy(ssl_certs[i].not_after, buf->data, min(sizeof(ssl_certs[i].not_after) - 1, (unsigned)buf->length)); ssl_certs[i].not_after[min(sizeof(ssl_certs[i].not_after) - 1, (unsigned)buf->length)] = 0; BUF_MEM_free(buf); ssl_certs[i].sig_type = X509_get_signature_type(certs[i].cert); ssl_certs[i].serial = ASN1_INTEGER_get( X509_get_serialNumber(certs[i].cert)); mem = BIO_new(BIO_s_mem()); X509_NAME_print_ex(mem, X509_get_issuer_name(certs[i].cert), 0, XN_FLAG_SEP_CPLUS_SPC | XN_FLAG_DN_REV | XN_FLAG_FN_NONE); BIO_get_mem_ptr(mem, &buf); (void) BIO_set_close(mem, BIO_NOCLOSE); BIO_free(mem); memcpy(ssl_certs[i].issuer, buf->data, min(sizeof(ssl_certs[i].issuer) - 1, (unsigned) buf->length)); ssl_certs[i].issuer[min(sizeof(ssl_certs[i].issuer) - 1, (unsigned) buf->length)] = 0; BUF_MEM_free(buf); mem = BIO_new(BIO_s_mem()); X509_NAME_print_ex(mem, X509_get_subject_name(certs[i].cert), 0, XN_FLAG_SEP_CPLUS_SPC | XN_FLAG_DN_REV | XN_FLAG_FN_NONE); BIO_get_mem_ptr(mem, &buf); (void) BIO_set_close(mem, BIO_NOCLOSE); BIO_free(mem); memcpy(ssl_certs[i].subject, buf->data, min(sizeof(ssl_certs[i].subject) - 1, (unsigned)buf->length)); ssl_certs[i].subject[min(sizeof(ssl_certs[i].subject) - 1, (unsigned) buf->length)] = 0; BUF_MEM_free(buf); ssl_certs[i].cert_type = X509_certificate_type(certs[i].cert, X509_get_pubkey(certs[i].cert)); /* and clean up */ certs[i].cert->references--; if (certs[i].cert->references == 0) X509_free(certs[i].cert); } msg.type = FETCH_CERT_ERR; msg.data.cert_err.certs = ssl_certs; msg.data.cert_err.num_certs = i; fetch_send_callback(&msg, f->fetch_handle); } else if (error) { switch (result) { case CURLE_SSL_CONNECT_ERROR: msg.type = FETCH_SSL_ERR; break; case CURLE_OPERATION_TIMEDOUT: msg.type = FETCH_TIMEDOUT; msg.data.error = curl_easy_strerror(result); break; default: msg.type = FETCH_ERROR; msg.data.error = curl_easy_strerror(result); } fetch_send_callback(&msg, f->fetch_handle); } fetch_free(f->fetch_handle); }