void doit(void) { int ret; gnutls_datum_t data; gnutls_x509_crt_t *crts; unsigned int crts_size, i; gnutls_x509_trust_list_t tl; unsigned int status, flags = GNUTLS_VERIFY_ALLOW_UNSORTED_CHAIN; unsigned int not_flags = GNUTLS_VERIFY_DO_NOT_ALLOW_UNSORTED_CHAIN; /* this must be called once in the program */ global_init(); gnutls_global_set_time_function(mytime); gnutls_global_set_log_function(tls_log_func); if (debug) gnutls_global_set_log_level(6); /* test for gnutls_certificate_get_issuer() */ gnutls_x509_trust_list_init(&tl, 0); ret = gnutls_x509_trust_list_add_trust_mem(tl, &ca, NULL, GNUTLS_X509_FMT_PEM, 0, 0); if (ret < 0) { fail("gnutls_x509_trust_list_add_trust_mem\n"); exit(1); } /* Chain 1 */ data.data = (void *) chain1; data.size = sizeof(chain1); ret = gnutls_x509_crt_list_import2(&crts, &crts_size, &data, GNUTLS_X509_FMT_PEM, 0); if (ret < 0) { fail("gnutls_x509_crt_list_import2: %s\n", gnutls_strerror(ret)); exit(1); } ret = gnutls_x509_trust_list_verify_crt(tl, crts, crts_size, flags, &status, NULL); if (ret < 0 || status != 0) { fail("gnutls_x509_trust_list_verify_crt - 1\n"); exit(1); } for (i = 0; i < crts_size; i++) gnutls_x509_crt_deinit(crts[i]); gnutls_free(crts); /* Chain 2 */ data.data = (void *) chain2; data.size = sizeof(chain2); /* verify whether the GNUTLS_X509_CRT_LIST_FAIL_IF_UNSORTED flag is * considered by gnutls_x509_crt_list_import2() */ ret = gnutls_x509_crt_list_import2(&crts, &crts_size, &data, GNUTLS_X509_FMT_PEM, GNUTLS_X509_CRT_LIST_FAIL_IF_UNSORTED); if (ret != GNUTLS_E_CERTIFICATE_LIST_UNSORTED) { fail("gnutls_x509_crt_list_import2 with flag GNUTLS_E_CERTIFICATE_LIST_UNSORTED on unsorted chain didn't fail: %s\n", gnutls_strerror(ret)); exit(1); } ret = gnutls_x509_crt_list_import2(&crts, &crts_size, &data, GNUTLS_X509_FMT_PEM, 0); if (ret < 0) { fail("gnutls_x509_crt_list_import2: %s\n", gnutls_strerror(ret)); exit(1); } ret = gnutls_x509_trust_list_verify_crt(tl, crts, crts_size, flags, &status, NULL); if (ret < 0 || status != 0) { fail("gnutls_x509_trust_list_verify_crt - 2\n"); exit(1); } for (i = 0; i < crts_size; i++) gnutls_x509_crt_deinit(crts[i]); gnutls_free(crts); /* Chain 3 */ data.data = (void *) chain3; data.size = sizeof(chain3); ret = gnutls_x509_crt_list_import2(&crts, &crts_size, &data, GNUTLS_X509_FMT_PEM, 0); if (ret < 0) { fail("gnutls_x509_crt_list_import2: %s\n", gnutls_strerror(ret)); exit(1); } ret = gnutls_x509_trust_list_verify_crt(tl, crts, crts_size, flags, &status, NULL); if (ret < 0 || status != 0) { fail("gnutls_x509_trust_list_verify_crt - 3\n"); exit(1); } for (i = 0; i < crts_size; i++) gnutls_x509_crt_deinit(crts[i]); gnutls_free(crts); /* Chain 4 */ data.data = (void *) chain4; data.size = sizeof(chain4); ret = gnutls_x509_crt_list_import2(&crts, &crts_size, &data, GNUTLS_X509_FMT_PEM, 0); if (ret < 0) { fail("gnutls_x509_crt_list_import2: %s\n", gnutls_strerror(ret)); exit(1); } ret = gnutls_x509_trust_list_verify_crt(tl, crts, crts_size, flags, &status, NULL); if (ret < 0 || status != 0) { fail("gnutls_x509_trust_list_verify_crt - 4\n"); exit(1); } for (i = 0; i < crts_size; i++) gnutls_x509_crt_deinit(crts[i]); gnutls_free(crts); /* Check if an unsorted list would fail if the unsorted flag is not given */ data.data = (void *) chain2; data.size = sizeof(chain2); ret = gnutls_x509_crt_list_import2(&crts, &crts_size, &data, GNUTLS_X509_FMT_PEM, 0); if (ret < 0) { fail("gnutls_x509_crt_list_import2: %s\n", gnutls_strerror(ret)); exit(1); } ret = gnutls_x509_trust_list_verify_crt(tl, crts, crts_size, not_flags, &status, NULL); if (ret < 0 || status == 0) { fail("gnutls_x509_trust_list_verify_crt - 5\n"); exit(1); } for (i = 0; i < crts_size; i++) gnutls_x509_crt_deinit(crts[i]); gnutls_free(crts); gnutls_x509_trust_list_deinit(tl, 1); gnutls_global_deinit(); if (debug) success("success"); }
void doit (void) { const char *filename, *password = "******"; gnutls_pkcs12_t pkcs12; unsigned char* file_data; size_t file_size; gnutls_datum_t data; gnutls_x509_crt_t * chain, * extras; unsigned int chain_size, extras_size, i; gnutls_x509_privkey_t pkey; int ret; ret = gnutls_global_init (); if (ret < 0) fail ("gnutls_global_init failed %d\n", ret); gnutls_global_set_log_function (tls_log_func); if (debug) gnutls_global_set_log_level (2); ret = gnutls_pkcs12_init(&pkcs12); if (ret < 0) fail ("initialization failed: %s\n", gnutls_strerror(ret)); filename = getenv ("PKCS12_MANY_CERTS_FILE"); if (!filename) filename = "pkcs12-decode/pkcs12_5certs.p12"; if (debug) success ("Reading PKCS#12 blob from `%s' using password `%s'.\n", filename, password); file_data = (void*)read_binary_file( filename, &file_size); if (file_data == NULL) fail("cannot open file"); data.data = file_data; data.size = file_size; ret = gnutls_pkcs12_import(pkcs12, &data, GNUTLS_X509_FMT_DER, 0); if (ret < 0) fail ("pkcs12_import failed %d: %s\n", ret, gnutls_strerror (ret)); if (debug) success ("Read file OK\n"); ret = gnutls_pkcs12_simple_parse (pkcs12, password, &pkey, &chain, &chain_size, &extras, &extras_size, NULL, 0); if (ret < 0) fail ("pkcs12_simple_parse failed %d: %s\n", ret, gnutls_strerror (ret)); if (chain_size != 1) fail("chain size (%u) should have been 1\n", chain_size); if (extras_size != 4) fail("extras size (%u) should have been 4\n", extras_size); if (debug) { char dn[512]; size_t dn_size; dn_size = sizeof(dn); ret = gnutls_x509_crt_get_dn(chain[0], dn, &dn_size); if (ret < 0) fail ("crt_get_dn failed %d: %s\n", ret, gnutls_strerror (ret)); success("dn: %s\n", dn); dn_size = sizeof(dn); ret = gnutls_x509_crt_get_issuer_dn(chain[0], dn, &dn_size); if (ret < 0) fail ("crt_get_dn failed %d: %s\n", ret, gnutls_strerror (ret)); success("issuer dn: %s\n", dn); } gnutls_pkcs12_deinit(pkcs12); gnutls_x509_privkey_deinit(pkey); for (i=0;i<chain_size;i++) gnutls_x509_crt_deinit(chain[i]); gnutls_free(chain); for (i=0;i<extras_size;i++) gnutls_x509_crt_deinit(extras[i]); gnutls_free(extras); /* Try gnutls_x509_privkey_import2() */ ret = gnutls_x509_privkey_init(&pkey); if (ret < 0) fail ("gnutls_x509_privkey_init failed %d: %s\n", ret, gnutls_strerror (ret)); ret = gnutls_x509_privkey_import2(pkey, &data, GNUTLS_X509_FMT_DER, password, 0); if (ret < 0) fail ("gnutls_x509_privkey_import2 failed %d: %s\n", ret, gnutls_strerror (ret)); gnutls_x509_privkey_deinit(pkey); free(file_data); gnutls_global_deinit (); }
void VerifyCertificate() { unsigned int certstatus; const gnutls_datum_t* cert_list; int ret; unsigned int cert_list_size; gnutls_x509_crt_t cert; char str[512]; unsigned char digest[512]; size_t digest_size = sizeof(digest); size_t name_size = sizeof(str); ssl_cert* certinfo = new ssl_cert; this->certificate = certinfo; /* This verification function uses the trusted CAs in the credentials * structure. So you must have installed one or more CA certificates. */ ret = gnutls_certificate_verify_peers2(this->sess, &certstatus); if (ret < 0) { certinfo->error = std::string(gnutls_strerror(ret)); return; } certinfo->invalid = (certstatus & GNUTLS_CERT_INVALID); certinfo->unknownsigner = (certstatus & GNUTLS_CERT_SIGNER_NOT_FOUND); certinfo->revoked = (certstatus & GNUTLS_CERT_REVOKED); certinfo->trusted = !(certstatus & GNUTLS_CERT_SIGNER_NOT_CA); /* Up to here the process is the same for X.509 certificates and * OpenPGP keys. From now on X.509 certificates are assumed. This can * be easily extended to work with openpgp keys as well. */ if (gnutls_certificate_type_get(this->sess) != GNUTLS_CRT_X509) { certinfo->error = "No X509 keys sent"; return; } ret = gnutls_x509_crt_init(&cert); if (ret < 0) { certinfo->error = gnutls_strerror(ret); return; } cert_list_size = 0; cert_list = gnutls_certificate_get_peers(this->sess, &cert_list_size); if (cert_list == NULL) { certinfo->error = "No certificate was found"; goto info_done_dealloc; } /* This is not a real world example, since we only check the first * certificate in the given chain. */ ret = gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER); if (ret < 0) { certinfo->error = gnutls_strerror(ret); goto info_done_dealloc; } if (gnutls_x509_crt_get_dn(cert, str, &name_size) == 0) { std::string& dn = certinfo->dn; dn = str; // Make sure there are no chars in the string that we consider invalid if (dn.find_first_of("\r\n") != std::string::npos) dn.clear(); } name_size = sizeof(str); if (gnutls_x509_crt_get_issuer_dn(cert, str, &name_size) == 0) { std::string& issuer = certinfo->issuer; issuer = str; if (issuer.find_first_of("\r\n") != std::string::npos) issuer.clear(); } if ((ret = gnutls_x509_crt_get_fingerprint(cert, profile->GetHash(), digest, &digest_size)) < 0) { certinfo->error = gnutls_strerror(ret); } else { certinfo->fingerprint = BinToHex(digest, digest_size); } /* Beware here we do not check for errors. */ if ((gnutls_x509_crt_get_expiration_time(cert) < ServerInstance->Time()) || (gnutls_x509_crt_get_activation_time(cert) > ServerInstance->Time())) { certinfo->error = "Not activated, or expired certificate"; } info_done_dealloc: gnutls_x509_crt_deinit(cert); }
/*- * gnutls_x509_extract_certificate_issuer_dn: * @cert: should contain an X.509 DER encoded certificate * @ret: a pointer to a structure to hold the issuer's name * * This function will return the name of the issuer stated in the certificate. The name is a gnutls_x509_dn structure and * is a obtained by the peer's certificate. If the certificate send by the * peer is invalid, or in any other failure this function returns error. * Returns a negative error code in case of an error. -*/ int gnutls_x509_extract_certificate_issuer_dn(const gnutls_datum_t * cert, gnutls_x509_dn * ret) { gnutls_x509_crt_t xcert; int result; size_t len; result = gnutls_x509_crt_init(&xcert); if (result < 0) return result; result = gnutls_x509_crt_import(xcert, cert, GNUTLS_X509_FMT_DER); if (result < 0) { gnutls_x509_crt_deinit(xcert); return result; } len = sizeof(ret->country); gnutls_x509_crt_get_issuer_dn_by_oid(xcert, GNUTLS_OID_X520_COUNTRY_NAME, 0, 0, ret->country, &len); len = sizeof(ret->organization); gnutls_x509_crt_get_issuer_dn_by_oid(xcert, GNUTLS_OID_X520_ORGANIZATION_NAME, 0, 0, ret->organization, &len); len = sizeof(ret->organizational_unit_name); gnutls_x509_crt_get_issuer_dn_by_oid(xcert, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, 0, 0, ret->organizational_unit_name, &len); len = sizeof(ret->common_name); gnutls_x509_crt_get_issuer_dn_by_oid(xcert, GNUTLS_OID_X520_COMMON_NAME, 0, 0, ret->common_name, &len); len = sizeof(ret->locality_name); gnutls_x509_crt_get_issuer_dn_by_oid(xcert, GNUTLS_OID_X520_LOCALITY_NAME, 0, 0, ret->locality_name, &len); len = sizeof(ret->state_or_province_name); gnutls_x509_crt_get_issuer_dn_by_oid(xcert, GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME, 0, 0, ret->state_or_province_name, &len); len = sizeof(ret->email); gnutls_x509_crt_get_issuer_dn_by_oid(xcert, GNUTLS_OID_PKCS9_EMAIL, 0, 0, ret->email, &len); gnutls_x509_crt_deinit(xcert); return 0; }
static int /* O - 1 on success, 0 on failure */ make_certificate(cupsd_client_t *con) /* I - Client connection */ { gnutls_x509_crt crt; /* Self-signed certificate */ gnutls_x509_privkey key; /* Encryption key */ cups_lang_t *language; /* Default language info */ cups_file_t *fp; /* Key/cert file */ unsigned char buffer[8192]; /* Buffer for x509 data */ size_t bytes; /* Number of bytes of data */ unsigned char serial[4]; /* Serial number buffer */ time_t curtime; /* Current time */ int result; /* Result of GNU TLS calls */ /* * Create the encryption key... */ cupsdLogMessage(CUPSD_LOG_INFO, "Generating SSL server key..."); gnutls_x509_privkey_init(&key); gnutls_x509_privkey_generate(key, GNUTLS_PK_RSA, 2048, 0); /* * Save it... */ bytes = sizeof(buffer); if ((result = gnutls_x509_privkey_export(key, GNUTLS_X509_FMT_PEM, buffer, &bytes)) < 0) { cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to export SSL server key - %s", gnutls_strerror(result)); gnutls_x509_privkey_deinit(key); return (0); } else if ((fp = cupsFileOpen(ServerKey, "w")) != NULL) { cupsFileWrite(fp, (char *)buffer, bytes); cupsFileClose(fp); cupsdLogMessage(CUPSD_LOG_INFO, "Created SSL server key file \"%s\"...", ServerKey); } else { cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create SSL server key file \"%s\" - %s", ServerKey, strerror(errno)); gnutls_x509_privkey_deinit(key); return (0); } /* * Create the self-signed certificate... */ cupsdLogMessage(CUPSD_LOG_INFO, "Generating self-signed SSL certificate..."); language = cupsLangDefault(); curtime = time(NULL); serial[0] = curtime >> 24; serial[1] = curtime >> 16; serial[2] = curtime >> 8; serial[3] = curtime; gnutls_x509_crt_init(&crt); if (strlen(language->language) == 5) gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COUNTRY_NAME, 0, language->language + 3, 2); else gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COUNTRY_NAME, 0, "US", 2); gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COMMON_NAME, 0, ServerName, strlen(ServerName)); gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_ORGANIZATION_NAME, 0, ServerName, strlen(ServerName)); gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, 0, "Unknown", 7); gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME, 0, "Unknown", 7); gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_LOCALITY_NAME, 0, "Unknown", 7); gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_PKCS9_EMAIL, 0, ServerAdmin, strlen(ServerAdmin)); gnutls_x509_crt_set_key(crt, key); gnutls_x509_crt_set_serial(crt, serial, sizeof(serial)); gnutls_x509_crt_set_activation_time(crt, curtime); gnutls_x509_crt_set_expiration_time(crt, curtime + 10 * 365 * 86400); gnutls_x509_crt_set_ca_status(crt, 0); gnutls_x509_crt_set_subject_alternative_name(crt, GNUTLS_SAN_DNSNAME, ServerName); gnutls_x509_crt_set_key_purpose_oid(crt, GNUTLS_KP_TLS_WWW_SERVER, 0); gnutls_x509_crt_set_key_usage(crt, GNUTLS_KEY_KEY_ENCIPHERMENT); gnutls_x509_crt_set_version(crt, 3); bytes = sizeof(buffer); if (gnutls_x509_crt_get_key_id(crt, 0, buffer, &bytes) >= 0) gnutls_x509_crt_set_subject_key_id(crt, buffer, bytes); gnutls_x509_crt_sign(crt, crt, key); /* * Save it... */ bytes = sizeof(buffer); if ((result = gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_PEM, buffer, &bytes)) < 0) cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to export SSL server certificate - %s", gnutls_strerror(result)); else if ((fp = cupsFileOpen(ServerCertificate, "w")) != NULL) { cupsFileWrite(fp, (char *)buffer, bytes); cupsFileClose(fp); cupsdLogMessage(CUPSD_LOG_INFO, "Created SSL server certificate file \"%s\"...", ServerCertificate); } else cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create SSL server certificate file \"%s\" - %s", ServerCertificate, strerror(errno)); /* * Cleanup... */ gnutls_x509_crt_deinit(crt); gnutls_x509_privkey_deinit(key); return (1); }
/** * gnutls_pkcs12_simple_parse: * @p12: the PKCS#12 blob. * @password: optional password used to decrypt PKCS#12 blob, bags and keys. * @key: a structure to store the parsed private key. * @chain: the corresponding to key certificate chain * @chain_len: will be updated with the number of additional * @extra_certs: optional pointer to receive an array of additional * certificates found in the PKCS#12 blob. * @extra_certs_len: will be updated with the number of additional * certs. * @crl: an optional structure to store the parsed CRL. * @flags: should be zero * * This function parses a PKCS#12 blob in @p12blob and extracts the * private key, the corresponding certificate chain, and any additional * certificates and a CRL. * * The @extra_certs_ret and @extra_certs_ret_len parameters are optional * and both may be set to %NULL. If either is non-%NULL, then both must * be. * * MAC:ed PKCS#12 files are supported. Encrypted PKCS#12 bags are * supported. Encrypted PKCS#8 private keys are supported. However, * only password based security, and the same password for all * operations, are supported. * * The private keys may be RSA PKCS#1 or DSA private keys encoded in * the OpenSSL way. * * PKCS#12 file may contain many keys and/or certificates, and there * is no way to identify which key/certificate pair you want. You * should make sure the PKCS#12 file only contain one key/certificate * pair and/or one CRL. * * It is believed that the limitations of this function is acceptable * for most usage, and that any more flexibility would introduce * complexity that would make it harder to use this functionality at * all. * * If the provided structure has encrypted fields but no password * is provided then this function returns %GNUTLS_E_DECRYPTION_FAILED. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 3.1 **/ int gnutls_pkcs12_simple_parse (gnutls_pkcs12_t p12, const char *password, gnutls_x509_privkey_t * key, gnutls_x509_crt_t ** chain, unsigned int * chain_len, gnutls_x509_crt_t ** extra_certs, unsigned int * extra_certs_len, gnutls_x509_crl_t * crl, unsigned int flags) { gnutls_pkcs12_bag_t bag = NULL; gnutls_x509_crt_t *_extra_certs = NULL; unsigned int _extra_certs_len = 0; gnutls_x509_crt_t *_chain = NULL; unsigned int _chain_len = 0; int idx = 0; int ret; size_t cert_id_size = 0; size_t key_id_size = 0; opaque cert_id[20]; opaque key_id[20]; int privkey_ok = 0; *key = NULL; if (crl) *crl = NULL; /* find the first private key */ for (;;) { int elements_in_bag; int i; ret = gnutls_pkcs12_bag_init (&bag); if (ret < 0) { bag = NULL; gnutls_assert (); goto done; } ret = gnutls_pkcs12_get_bag (p12, idx, bag); if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) break; if (ret < 0) { gnutls_assert (); goto done; } ret = gnutls_pkcs12_bag_get_type (bag, 0); if (ret < 0) { gnutls_assert (); goto done; } if (ret == GNUTLS_BAG_ENCRYPTED) { if (password == NULL) { ret = gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); goto done; } ret = gnutls_pkcs12_bag_decrypt (bag, password); if (ret < 0) { gnutls_assert (); goto done; } } elements_in_bag = gnutls_pkcs12_bag_get_count (bag); if (elements_in_bag < 0) { gnutls_assert (); goto done; } for (i = 0; i < elements_in_bag; i++) { int type; gnutls_datum_t data; type = gnutls_pkcs12_bag_get_type (bag, i); if (type < 0) { gnutls_assert (); goto done; } ret = gnutls_pkcs12_bag_get_data (bag, i, &data); if (ret < 0) { gnutls_assert (); goto done; } switch (type) { case GNUTLS_BAG_PKCS8_ENCRYPTED_KEY: if (password == NULL) { ret = gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); goto done; } case GNUTLS_BAG_PKCS8_KEY: if (*key != NULL) /* too simple to continue */ { gnutls_assert (); break; } ret = gnutls_x509_privkey_init (key); if (ret < 0) { gnutls_assert (); goto done; } ret = gnutls_x509_privkey_import_pkcs8 (*key, &data, GNUTLS_X509_FMT_DER, password, type == GNUTLS_BAG_PKCS8_KEY ? GNUTLS_PKCS_PLAIN : 0); if (ret < 0) { gnutls_assert (); gnutls_x509_privkey_deinit (*key); goto done; } key_id_size = sizeof (key_id); ret = gnutls_x509_privkey_get_key_id (*key, 0, key_id, &key_id_size); if (ret < 0) { gnutls_assert (); gnutls_x509_privkey_deinit (*key); goto done; } privkey_ok = 1; /* break */ break; default: break; } } idx++; gnutls_pkcs12_bag_deinit (bag); if (privkey_ok != 0) /* private key was found */ break; } if (privkey_ok == 0) /* no private key */ { gnutls_assert (); return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; } /* now find the corresponding certificate */ idx = 0; bag = NULL; for (;;) { int elements_in_bag; int i; ret = gnutls_pkcs12_bag_init (&bag); if (ret < 0) { bag = NULL; gnutls_assert (); goto done; } ret = gnutls_pkcs12_get_bag (p12, idx, bag); if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) break; if (ret < 0) { gnutls_assert (); goto done; } ret = gnutls_pkcs12_bag_get_type (bag, 0); if (ret < 0) { gnutls_assert (); goto done; } if (ret == GNUTLS_BAG_ENCRYPTED) { ret = gnutls_pkcs12_bag_decrypt (bag, password); if (ret < 0) { gnutls_assert (); goto done; } } elements_in_bag = gnutls_pkcs12_bag_get_count (bag); if (elements_in_bag < 0) { gnutls_assert (); goto done; } for (i = 0; i < elements_in_bag; i++) { int type; gnutls_datum_t data; gnutls_x509_crt_t this_cert; type = gnutls_pkcs12_bag_get_type (bag, i); if (type < 0) { gnutls_assert (); goto done; } ret = gnutls_pkcs12_bag_get_data (bag, i, &data); if (ret < 0) { gnutls_assert (); goto done; } switch (type) { case GNUTLS_BAG_CERTIFICATE: ret = gnutls_x509_crt_init (&this_cert); if (ret < 0) { gnutls_assert (); goto done; } ret = gnutls_x509_crt_import (this_cert, &data, GNUTLS_X509_FMT_DER); if (ret < 0) { gnutls_assert (); gnutls_x509_crt_deinit (this_cert); goto done; } /* check if the key id match */ cert_id_size = sizeof (cert_id); ret = gnutls_x509_crt_get_key_id (this_cert, 0, cert_id, &cert_id_size); if (ret < 0) { gnutls_assert (); gnutls_x509_crt_deinit (this_cert); goto done; } if (memcmp (cert_id, key_id, cert_id_size) != 0) { /* they don't match - skip the certificate */ if (extra_certs) { void *tmp = _extra_certs; _extra_certs = gnutls_realloc (_extra_certs, sizeof(_extra_certs[0]) * ++_extra_certs_len); if (!_extra_certs) { gnutls_assert (); gnutls_free(tmp); ret = GNUTLS_E_MEMORY_ERROR; goto done; } _extra_certs[_extra_certs_len - 1] = this_cert; this_cert = NULL; } else { gnutls_x509_crt_deinit (this_cert); } } else { if (_chain_len == 0) { _chain = gnutls_malloc (sizeof(_chain[0]) * (++_chain_len)); if (!_chain) { gnutls_assert (); ret = GNUTLS_E_MEMORY_ERROR; goto done; } _chain[_chain_len - 1] = this_cert; this_cert = NULL; } else { gnutls_x509_crt_deinit (this_cert); } } break; case GNUTLS_BAG_CRL: if (crl == NULL || *crl != NULL) { gnutls_assert (); break; } ret = gnutls_x509_crl_init (crl); if (ret < 0) { gnutls_assert (); goto done; } ret = gnutls_x509_crl_import (*crl, &data, GNUTLS_X509_FMT_DER); if (ret < 0) { gnutls_assert (); gnutls_x509_crl_deinit (*crl); goto done; } break; case GNUTLS_BAG_ENCRYPTED: /* XXX Bother to recurse one level down? Unlikely to use the same password anyway. */ case GNUTLS_BAG_EMPTY: default: break; } } idx++; gnutls_pkcs12_bag_deinit (bag); } if (_chain_len != 1) { ret = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; goto done; } ret = make_chain(&_chain, &_chain_len, &_extra_certs, &_extra_certs_len); if (ret < 0) { gnutls_assert(); goto done; } ret = 0; done: if (bag) gnutls_pkcs12_bag_deinit (bag); if (ret < 0) { if (*key) gnutls_x509_privkey_deinit(*key); if (_extra_certs_len && _extra_certs != NULL) { unsigned int i; for (i = 0; i < _extra_certs_len; i++) gnutls_x509_crt_deinit(_extra_certs[i]); gnutls_free(_extra_certs); } if (_chain_len && _chain != NULL) { unsigned int i; for (i = 0; i < _chain_len; i++) gnutls_x509_crt_deinit(_chain[i]); gnutls_free(_chain); } } else { if (extra_certs) { *extra_certs = _extra_certs; *extra_certs_len = _extra_certs_len; } *chain = _chain; *chain_len = _chain_len; } return ret; }
int ssl_open(http_t *client, char *msg) { int ret; char buf[256]; size_t len; const char *sn, *err; const gnutls_datum_t *cert_list; unsigned int cert_list_size = 0; gnutls_x509_crt_t cert; if (!client->ssl_enabled) return tcp_init(&client->tcp, msg); /* Initialize TLS session */ logit(LOG_INFO, "%s, initiating HTTPS ...", msg); gnutls_init(&client->ssl, GNUTLS_CLIENT); /* SSL SNI support: tell the servername we want to speak to */ http_get_remote_name(client, &sn); gnutls_session_set_ptr(client->ssl, (void *)sn); if (gnutls_server_name_set(client->ssl, GNUTLS_NAME_DNS, sn, strlen(sn))) return RC_HTTPS_SNI_ERROR; /* Use default priorities */ ret = gnutls_priority_set_direct(client->ssl, "NORMAL", &err); if (ret < 0) { if (ret == GNUTLS_E_INVALID_REQUEST) logit(LOG_ERR, "Syntax error at: %s", err); return RC_HTTPS_INVALID_REQUEST; } /* put the x509 credentials to the current session */ gnutls_credentials_set(client->ssl, GNUTLS_CRD_CERTIFICATE, xcred); /* connect to the peer */ tcp_set_port(&client->tcp, HTTPS_DEFAULT_PORT); DO(tcp_init(&client->tcp, msg)); /* Forward TCP socket to GnuTLS, the set_int() API is perhaps too new still ... since 3.1.9 */ // gnutls_transport_set_int(client->ssl, client->tcp.ip.socket); gnutls_transport_set_ptr(client->ssl, (gnutls_transport_ptr_t)(intptr_t)client->tcp.ip.socket); /* Perform the TLS handshake, ignore non-fatal errors. */ do { ret = gnutls_handshake(client->ssl); } while (ret != 0 && !gnutls_error_is_fatal(ret)); if (gnutls_error_is_fatal(ret)) { logit(LOG_ERR, "SSL handshake with %s failed: %s", sn, gnutls_strerror(ret)); return RC_HTTPS_FAILED_CONNECT; } ssl_get_info(client); /* Get server's certificate (note: beware of dynamic allocation) - opt */ cert_list = gnutls_certificate_get_peers(client->ssl, &cert_list_size); if (cert_list_size > 0) { if (gnutls_x509_crt_init(&cert)) return RC_HTTPS_FAILED_GETTING_CERT; gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER); len = sizeof(buf); gnutls_x509_crt_get_dn(cert, buf, &len); logit(LOG_INFO, "SSL server cert subject: %s", buf); len = sizeof(buf); gnutls_x509_crt_get_issuer_dn(cert, buf, &len); logit(LOG_INFO, "SSL server cert issuer: %s", buf); gnutls_x509_crt_deinit(cert); } return 0; }
~GnuTLSX509CertificateInternalData() { gnutls_x509_crt_deinit(cert); }
/** * gnutls_x509_trust_list_add_cas: * @list: The structure of the list * @clist: A list of CAs * @clist_size: The length of the CA list * @flags: should be 0 or an or'ed sequence of %GNUTLS_TL options. * * This function will add the given certificate authorities * to the trusted list. The list of CAs must not be deinitialized * during this structure's lifetime. * * If the flag %GNUTLS_TL_NO_DUPLICATES is specified, then * the provided @clist entries that are duplicates will not be * added to the list and will be deinitialized. * * Returns: The number of added elements is returned. * * Since: 3.0.0 **/ int gnutls_x509_trust_list_add_cas(gnutls_x509_trust_list_t list, const gnutls_x509_crt_t * clist, unsigned clist_size, unsigned int flags) { unsigned i, j; uint32_t hash; int ret; unsigned exists; for (i = 0; i < clist_size; i++) { exists = 0; hash = hash_pjw_bare(clist[i]->raw_dn.data, clist[i]->raw_dn.size); hash %= list->size; /* avoid duplicates */ if (flags & GNUTLS_TL_NO_DUPLICATES || flags & GNUTLS_TL_NO_DUPLICATE_KEY) { for (j=0;j<list->node[hash].trusted_ca_size;j++) { if (flags & GNUTLS_TL_NO_DUPLICATES) ret = _gnutls_check_if_same_cert(list->node[hash].trusted_cas[j], clist[i]); else ret = _gnutls_check_if_same_key(list->node[hash].trusted_cas[j], clist[i], 1); if (ret != 0) { exists = 1; break; } } if (exists != 0) { gnutls_x509_crt_deinit(list->node[hash].trusted_cas[j]); list->node[hash].trusted_cas[j] = clist[i]; continue; } } list->node[hash].trusted_cas = gnutls_realloc_fast(list->node[hash].trusted_cas, (list->node[hash].trusted_ca_size + 1) * sizeof(list->node[hash]. trusted_cas[0])); if (list->node[hash].trusted_cas == NULL) { gnutls_assert(); return i; } if (gnutls_x509_crt_get_version(clist[i]) >= 3 && gnutls_x509_crt_get_ca_status(clist[i], NULL) <= 0) { gnutls_datum_t dn; gnutls_assert(); if (gnutls_x509_crt_get_dn2(clist[i], &dn) >= 0) { _gnutls_audit_log(NULL, "There was a non-CA certificate in the trusted list: %s.\n", dn.data); gnutls_free(dn.data); } } list->node[hash].trusted_cas[list->node[hash]. trusted_ca_size] = clist[i]; list->node[hash].trusted_ca_size++; if (flags & GNUTLS_TL_USE_IN_TLS) { ret = add_new_ca_to_rdn_seq(list, clist[i]); if (ret < 0) { gnutls_assert(); return i; } } } return i; }
/* Reads a certificate key from a token. */ static int read_cert_url(gnutls_certificate_credentials_t res, gnutls_privkey_t key, const char *url) { int ret; gnutls_x509_crt_t crt = NULL; gnutls_pcert_st *ccert = NULL; gnutls_str_array_t names; gnutls_datum_t t = {NULL, 0}; unsigned i, count = 0; _gnutls_str_array_init(&names); ccert = gnutls_malloc(sizeof(*ccert)*MAX_PKCS11_CERT_CHAIN); if (ccert == NULL) { gnutls_assert(); ret = GNUTLS_E_MEMORY_ERROR; goto cleanup; } ret = gnutls_x509_crt_init(&crt); if (ret < 0) { gnutls_assert(); goto cleanup; } if (res->pin.cb) gnutls_x509_crt_set_pin_function(crt, res->pin.cb, res->pin.data); ret = gnutls_x509_crt_import_url(crt, url, 0); if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) ret = gnutls_x509_crt_import_url(crt, url, GNUTLS_PKCS11_OBJ_FLAG_LOGIN); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = _gnutls_get_x509_name(crt, &names); if (ret < 0) { gnutls_assert(); goto cleanup; } /* Try to load the whole certificate chain from the PKCS #11 token */ for (i=0;i<MAX_PKCS11_CERT_CHAIN;i++) { ret = gnutls_x509_crt_check_issuer(crt, crt); if (i > 0 && ret != 0) { /* self signed */ break; } ret = gnutls_pcert_import_x509(&ccert[i], crt, 0); if (ret < 0) { gnutls_assert(); goto cleanup; } count++; ret = _gnutls_get_raw_issuer(url, crt, &t, 0); if (ret < 0) break; gnutls_x509_crt_deinit(crt); crt = NULL; ret = gnutls_x509_crt_init(&crt); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = gnutls_x509_crt_import(crt, &t, GNUTLS_X509_FMT_DER); if (ret < 0) { gnutls_assert(); goto cleanup; } gnutls_free(t.data); } ret = _gnutls_certificate_credential_append_keypair(res, key, names, ccert, count); if (ret < 0) { gnutls_assert(); goto cleanup; } if (crt != NULL) gnutls_x509_crt_deinit(crt); return 0; cleanup: if (crt != NULL) gnutls_x509_crt_deinit(crt); gnutls_free(t.data); _gnutls_str_array_clear(&names); gnutls_free(ccert); return ret; }
static int qcrypto_tls_session_check_certificate(QCryptoTLSSession *session, Error **errp) { int ret; unsigned int status; const gnutls_datum_t *certs; unsigned int nCerts, i; time_t now; gnutls_x509_crt_t cert = NULL; now = time(NULL); if (now == ((time_t)-1)) { error_setg_errno(errp, errno, "Cannot get current time"); return -1; } ret = gnutls_certificate_verify_peers2(session->handle, &status); if (ret < 0) { error_setg(errp, "Verify failed: %s", gnutls_strerror(ret)); return -1; } if (status != 0) { const char *reason = "Invalid certificate"; if (status & GNUTLS_CERT_INVALID) { reason = "The certificate is not trusted"; } if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) { reason = "The certificate hasn't got a known issuer"; } if (status & GNUTLS_CERT_REVOKED) { reason = "The certificate has been revoked"; } if (status & GNUTLS_CERT_INSECURE_ALGORITHM) { reason = "The certificate uses an insecure algorithm"; } error_setg(errp, "%s", reason); return -1; } certs = gnutls_certificate_get_peers(session->handle, &nCerts); if (!certs) { error_setg(errp, "No certificate peers"); return -1; } for (i = 0; i < nCerts; i++) { ret = gnutls_x509_crt_init(&cert); if (ret < 0) { error_setg(errp, "Cannot initialize certificate: %s", gnutls_strerror(ret)); return -1; } ret = gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER); if (ret < 0) { error_setg(errp, "Cannot import certificate: %s", gnutls_strerror(ret)); goto error; } if (gnutls_x509_crt_get_expiration_time(cert) < now) { error_setg(errp, "The certificate has expired"); goto error; } if (gnutls_x509_crt_get_activation_time(cert) > now) { error_setg(errp, "The certificate is not yet activated"); goto error; } if (gnutls_x509_crt_get_activation_time(cert) > now) { error_setg(errp, "The certificate is not yet activated"); goto error; } if (i == 0) { size_t dnameSize = 1024; session->peername = g_malloc(dnameSize); requery: ret = gnutls_x509_crt_get_dn(cert, session->peername, &dnameSize); if (ret < 0) { if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) { session->peername = g_realloc(session->peername, dnameSize); goto requery; } error_setg(errp, "Cannot get client distinguished name: %s", gnutls_strerror(ret)); goto error; } if (session->aclname) { qemu_acl *acl = qemu_acl_find(session->aclname); int allow; if (!acl) { error_setg(errp, "Cannot find ACL %s", session->aclname); goto error; } allow = qemu_acl_party_is_allowed(acl, session->peername); if (!allow) { error_setg(errp, "TLS x509 ACL check for %s is denied", session->peername); goto error; } } if (session->hostname) { if (!gnutls_x509_crt_check_hostname(cert, session->hostname)) { error_setg(errp, "Certificate does not match the hostname %s", session->hostname); goto error; } } } gnutls_x509_crt_deinit(cert); } return 0; error: gnutls_x509_crt_deinit(cert); return -1; }
/* Reads a base64 encoded certificate list from memory and stores it to * a gnutls_cert structure. Returns the number of certificate parsed. */ static int parse_pem_cert_mem(gnutls_certificate_credentials_t res, gnutls_privkey_t key, const char *input_cert, int input_cert_size) { int size; const char *ptr; gnutls_datum_t tmp; int ret, count, i; unsigned ncerts = 0; gnutls_pcert_st *pcerts = NULL; gnutls_str_array_t names; gnutls_x509_crt_t unsorted[DEFAULT_MAX_VERIFY_DEPTH]; _gnutls_str_array_init(&names); /* move to the certificate */ ptr = memmem(input_cert, input_cert_size, PEM_CERT_SEP, sizeof(PEM_CERT_SEP) - 1); if (ptr == NULL) ptr = memmem(input_cert, input_cert_size, PEM_CERT_SEP2, sizeof(PEM_CERT_SEP2) - 1); if (ptr == NULL) { gnutls_assert(); return GNUTLS_E_BASE64_DECODING_ERROR; } size = input_cert_size - (ptr - input_cert); count = 0; do { tmp.data = (void *) ptr; tmp.size = size; ret = gnutls_x509_crt_init(&unsorted[count]); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = gnutls_x509_crt_import(unsorted[count], &tmp, GNUTLS_X509_FMT_PEM); if (ret < 0) { gnutls_assert(); goto cleanup; } count++; /* now we move ptr after the pem header */ ptr++; size--; /* find the next certificate (if any) */ if (size > 0) { char *ptr3; ptr3 = memmem(ptr, size, PEM_CERT_SEP, sizeof(PEM_CERT_SEP) - 1); if (ptr3 == NULL) ptr3 = memmem(ptr, size, PEM_CERT_SEP2, sizeof(PEM_CERT_SEP2) - 1); ptr = ptr3; size = input_cert_size - (ptr - input_cert); } else ptr = NULL; } while (ptr != NULL && count < DEFAULT_MAX_VERIFY_DEPTH); ret = _gnutls_get_x509_name(unsorted[0], &names); if (ret < 0) { gnutls_assert(); goto cleanup; } pcerts = gnutls_malloc(sizeof(gnutls_pcert_st) * count); if (pcerts == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } ncerts = count; ret = gnutls_pcert_import_x509_list(pcerts, unsorted, &ncerts, GNUTLS_X509_CRT_LIST_SORT); if (ret < 0) { gnutls_free(pcerts); gnutls_assert(); goto cleanup; } ret = _gnutls_certificate_credential_append_keypair(res, key, names, pcerts, ncerts); if (ret < 0) { gnutls_assert(); goto cleanup; } for (i = 0; i < count; i++) gnutls_x509_crt_deinit(unsorted[i]); return ncerts; cleanup: _gnutls_str_array_clear(&names); for (i = 0; i < count; i++) gnutls_x509_crt_deinit(unsorted[i]); if (pcerts) { for (i = 0; i < count; i++) gnutls_pcert_deinit(&pcerts[i]); gnutls_free(pcerts); } return ret; }
/** * gnutls_certificate_set_x509_simple_pkcs12_mem: * @res: is a #gnutls_certificate_credentials_t type. * @p12blob: the PKCS#12 blob. * @type: is PEM or DER of the @pkcs12file. * @password: optional password used to decrypt PKCS#12 file, bags and keys. * * This function sets a certificate/private key pair and/or a CRL in * the gnutls_certificate_credentials_t type. This function may * be called more than once (in case multiple keys/certificates exist * for the server). * * Encrypted PKCS#12 bags and PKCS#8 private keys are supported. However, * only password based security, and the same password for all * operations, are supported. * * PKCS#12 file may contain many keys and/or certificates, and this * function will try to auto-detect based on the key ID the certificate * and key pair to use. If the PKCS#12 file contain the issuer of * the selected certificate, it will be appended to the certificate * to form a chain. * * If more than one private keys are stored in the PKCS#12 file, * then only one key will be read (and it is undefined which one). * * It is believed that the limitations of this function is acceptable * for most usage, and that any more flexibility would introduce * complexity that would make it harder to use this functionality at * all. * * Note that, this function by default returns zero on success and a negative value on error. * Since 3.5.6, when the flag %GNUTLS_CERTIFICATE_API_V2 is set using gnutls_certificate_set_flags() * it returns an index (greater or equal to zero). That index can be used to other functions to refer to the added key-pair. * * Returns: On success this functions returns zero, and otherwise a negative value on error (see above for modifying that behavior). * * Since: 2.8.0 **/ int gnutls_certificate_set_x509_simple_pkcs12_mem (gnutls_certificate_credentials_t res, const gnutls_datum_t * p12blob, gnutls_x509_crt_fmt_t type, const char *password) { gnutls_pkcs12_t p12; gnutls_x509_privkey_t key = NULL; gnutls_x509_crt_t *chain = NULL; gnutls_x509_crl_t crl = NULL; unsigned int chain_size = 0, i; int ret, idx; ret = gnutls_pkcs12_init(&p12); if (ret < 0) { gnutls_assert(); return ret; } ret = gnutls_pkcs12_import(p12, p12blob, type, 0); if (ret < 0) { gnutls_assert(); gnutls_pkcs12_deinit(p12); return ret; } if (password) { ret = gnutls_pkcs12_verify_mac(p12, password); if (ret < 0) { gnutls_assert(); gnutls_pkcs12_deinit(p12); return ret; } } ret = gnutls_pkcs12_simple_parse(p12, password, &key, &chain, &chain_size, NULL, NULL, &crl, 0); gnutls_pkcs12_deinit(p12); if (ret < 0) { gnutls_assert(); return ret; } if (key && chain) { ret = gnutls_certificate_set_x509_key(res, chain, chain_size, key); if (ret < 0) { gnutls_assert(); goto done; } idx = ret; } else { gnutls_assert(); ret = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; goto done; } if (crl) { ret = gnutls_certificate_set_x509_crl(res, &crl, 1); if (ret < 0) { gnutls_assert(); goto done; } } if (res->flags & GNUTLS_CERTIFICATE_API_V2) ret = idx; else ret = 0; done: if (chain) { for (i = 0; i < chain_size; i++) gnutls_x509_crt_deinit(chain[i]); gnutls_free(chain); } if (key) gnutls_x509_privkey_deinit(key); if (crl) gnutls_x509_crl_deinit(crl); return ret; }
/* Reads a DER encoded certificate list from memory and stores it to a * gnutls_cert structure. Returns the number of certificates parsed. */ static int parse_der_cert_mem(gnutls_certificate_credentials_t res, gnutls_privkey_t key, const void *input_cert, int input_cert_size) { gnutls_datum_t tmp; gnutls_x509_crt_t crt; gnutls_pcert_st *ccert; int ret; gnutls_str_array_t names; _gnutls_str_array_init(&names); ccert = gnutls_malloc(sizeof(*ccert)); if (ccert == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } ret = gnutls_x509_crt_init(&crt); if (ret < 0) { gnutls_assert(); goto cleanup; } tmp.data = (uint8_t *) input_cert; tmp.size = input_cert_size; ret = gnutls_x509_crt_import(crt, &tmp, GNUTLS_X509_FMT_DER); if (ret < 0) { gnutls_assert(); gnutls_x509_crt_deinit(crt); goto cleanup; } ret = _gnutls_get_x509_name(crt, &names); if (ret < 0) { gnutls_assert(); gnutls_x509_crt_deinit(crt); goto cleanup; } ret = gnutls_pcert_import_x509(ccert, crt, 0); gnutls_x509_crt_deinit(crt); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = _gnutls_certificate_credential_append_keypair(res, key, names, ccert, 1); if (ret < 0) { gnutls_assert(); goto cleanup; } return ret; cleanup: _gnutls_str_array_clear(&names); gnutls_free(ccert); return ret; }
void doit (void) { int ret; unsigned char der[] = { 0x30, 0x82, 0x03, 0x00, 0x30, 0x82, 0x01, 0xec, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0xbd, 0x76, 0xdf, 0x42, 0x47, 0x0a, 0x00, 0x8d, 0x47, 0x3e, 0x74, 0x3f, 0xa1, 0xdc, 0x8b, 0xbd, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1d, 0x05, 0x00, 0x30, 0x2d, 0x31, 0x2b, 0x30, 0x29, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x22, 0x77, 0x00, 0x32, 0x00, 0x6b, 0x00, 0x38, 0x00, 0x72, 0x00, 0x32, 0x00, 0x2e, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x74, 0x00, 0x77, 0x00, 0x73, 0x00, 0x2e, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x74, 0x00, 0x00, 0x00, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30, 0x30, 0x34, 0x32, 0x38, 0x31, 0x31, 0x34, 0x31, 0x35, 0x34, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30, 0x34, 0x32, 0x38, 0x31, 0x31, 0x34, 0x31, 0x35, 0x34, 0x5a, 0x30, 0x2d, 0x31, 0x2b, 0x30, 0x29, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x22, 0x77, 0x00, 0x32, 0x00, 0x6b, 0x00, 0x38, 0x00, 0x72, 0x00, 0x32, 0x00, 0x2e, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x74, 0x00, 0x77, 0x00, 0x73, 0x00, 0x2e, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x74, 0x00, 0x00, 0x00, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xaa, 0xd7, 0x32, 0x26, 0xd7, 0xfc, 0x69, 0x57, 0x4a, 0x55, 0x08, 0x2b, 0x97, 0xc1, 0x5b, 0x90, 0xfd, 0xe8, 0xf5, 0xf7, 0x9e, 0x7d, 0x34, 0xce, 0xe9, 0xbb, 0x38, 0xa0, 0x9f, 0xec, 0x84, 0x86, 0x3e, 0x47, 0x2e, 0x71, 0xd7, 0xc3, 0xbf, 0x89, 0xf3, 0x80, 0xb5, 0x77, 0x80, 0xd3, 0xb0, 0x56, 0x6b, 0x9c, 0xf4, 0xd3, 0x42, 0x2b, 0x26, 0x01, 0x5c, 0x42, 0xef, 0xf6, 0x51, 0x5a, 0xaa, 0x55, 0x6b, 0x30, 0xd3, 0x2c, 0xdc, 0xde, 0x36, 0x4d, 0xdd, 0xf3, 0x5f, 0x59, 0xba, 0x57, 0xd8, 0x39, 0x0f, 0x5b, 0xd3, 0xe1, 0x34, 0x39, 0x22, 0xaa, 0x71, 0x10, 0x59, 0x7a, 0xec, 0x9f, 0x1a, 0xf5, 0xa9, 0x40, 0xd6, 0x7b, 0x32, 0x5f, 0x19, 0x85, 0xc0, 0xfd, 0xa6, 0x6c, 0x32, 0x58, 0xdc, 0x7c, 0x07, 0x42, 0x36, 0xd0, 0x57, 0x78, 0x63, 0x60, 0x92, 0x1d, 0x1f, 0x9d, 0xbd, 0xcc, 0xd7, 0xe3, 0x1a, 0x57, 0xdb, 0x70, 0x80, 0x89, 0x36, 0x39, 0x01, 0x71, 0x5a, 0x2a, 0x05, 0x25, 0x13, 0x80, 0xf8, 0x49, 0x48, 0x5f, 0x06, 0xd0, 0xcb, 0x2c, 0x58, 0x9a, 0xe7, 0x8b, 0x6d, 0x17, 0x2c, 0xb2, 0x97, 0x2c, 0x15, 0xc9, 0x73, 0x6d, 0x8f, 0x4f, 0xf3, 0xf1, 0xb9, 0x70, 0x3f, 0xcb, 0x5f, 0x80, 0x85, 0x8b, 0xdf, 0xd2, 0x05, 0x95, 0x1c, 0xe4, 0x37, 0xee, 0xd2, 0x62, 0x49, 0x08, 0xdf, 0xf6, 0x02, 0xec, 0xe6, 0x9a, 0x37, 0xfc, 0x21, 0x7a, 0x98, 0x12, 0x1d, 0x79, 0xbf, 0xc7, 0x0f, 0x0a, 0x20, 0xf8, 0xef, 0xa5, 0xc6, 0x0e, 0x94, 0x5e, 0x17, 0x94, 0x12, 0x42, 0xfe, 0xd7, 0x22, 0xbd, 0x31, 0x27, 0xc7, 0xdb, 0x4a, 0x4e, 0x95, 0xe2, 0xc1, 0xdd, 0xe8, 0x0f, 0x7d, 0x1d, 0xe4, 0xfd, 0xb1, 0x27, 0x7b, 0xc1, 0x71, 0xfe, 0x27, 0x47, 0x89, 0xf4, 0xfc, 0x84, 0xa5, 0x57, 0x5d, 0x21, 0x02, 0x03, 0x01, 0x00, 0x01, 0x81, 0x11, 0x00, 0xbd, 0x8b, 0xdc, 0xa1, 0x3f, 0x74, 0x3e, 0x47, 0x8d, 0x00, 0x0a, 0x47, 0x42, 0xdf, 0x76, 0xbd, 0x82, 0x11, 0x00, 0xbd, 0x8b, 0xdc, 0xa1, 0x3f, 0x74, 0x3e, 0x47, 0x8d, 0x00, 0x0a, 0x47, 0x42, 0xdf, 0x76, 0xbd, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1d, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0xa7, 0xb0, 0x66, 0x75, 0x14, 0x7e, 0x7d, 0xb5, 0x31, 0xec, 0xb2, 0xeb, 0x90, 0x80, 0x95, 0x25, 0x59, 0x0f, 0xe4, 0x15, 0x86, 0x2d, 0x9d, 0xd7, 0x35, 0xe9, 0x22, 0x74, 0xe7, 0x85, 0x36, 0x19, 0x4f, 0x27, 0x5c, 0x17, 0x63, 0x7b, 0x2a, 0xfe, 0x59, 0xe9, 0x76, 0x77, 0xd0, 0xc9, 0x40, 0x78, 0x7c, 0x31, 0x62, 0x1e, 0x87, 0x1b, 0xc1, 0x19, 0xef, 0x6f, 0x15, 0xe6, 0xce, 0x74, 0x84, 0x6d, 0xd6, 0x3b, 0x57, 0xd9, 0xa9, 0x13, 0xf6, 0x7d, 0x84, 0xe7, 0x8f, 0xc6, 0x01, 0x5f, 0xcf, 0xc4, 0x95, 0xc9, 0xde, 0x97, 0x17, 0x43, 0x12, 0x70, 0x27, 0xf9, 0xc4, 0xd7, 0xe1, 0x05, 0xbb, 0x63, 0x87, 0x5f, 0xdc, 0x20, 0xbd, 0xd1, 0xde, 0xd6, 0x2d, 0x9f, 0x3f, 0x5d, 0x0a, 0x27, 0x40, 0x11, 0x5f, 0x5d, 0x54, 0xa7, 0x28, 0xf9, 0x03, 0x2e, 0x84, 0x8d, 0x48, 0x60, 0xa1, 0x71, 0xa3, 0x46, 0x69, 0xdb, 0x88, 0x7b, 0xc1, 0xb6, 0x08, 0x2d, 0xdf, 0x25, 0x9d, 0x32, 0x76, 0x49, 0x0b, 0xba, 0xab, 0xdd, 0xc3, 0x00, 0x76, 0x8a, 0x94, 0xd2, 0x25, 0x43, 0xf0, 0xa9, 0x98, 0x65, 0x94, 0xc7, 0xdd, 0x7c, 0xd4, 0xe2, 0xe8, 0x33, 0xe2, 0x9a, 0xe9, 0x75, 0xf0, 0x0f, 0x61, 0x86, 0xee, 0x0e, 0xf7, 0x39, 0x6b, 0x30, 0x63, 0xe5, 0x46, 0xd4, 0x1c, 0x83, 0xa1, 0x28, 0x79, 0x76, 0x81, 0x48, 0x38, 0x72, 0xbc, 0x3f, 0x25, 0x53, 0x31, 0xaa, 0x02, 0xd1, 0x9b, 0x03, 0xa2, 0x5c, 0x94, 0x21, 0xb3, 0x8e, 0xdf, 0x2a, 0xa5, 0x4c, 0x65, 0xa2, 0xf9, 0xac, 0x38, 0x7a, 0xf9, 0x45, 0xb3, 0xd5, 0xda, 0xe5, 0xb9, 0x56, 0x9e, 0x47, 0xd5, 0x06, 0xe6, 0xca, 0xd7, 0x6e, 0x06, 0xdb, 0x6e, 0xa7, 0x7b, 0x4b, 0x13, 0x40, 0x3c, 0x12, 0x76, 0x99, 0x65, 0xb4, 0x54, 0xa1, 0xd8, 0x21, 0x5c, 0x27 }; gnutls_datum_t derCert = { der, sizeof (der) }; gnutls_x509_crt_t cert; int result; unsigned char expectedId[] = { 0xbd, 0x8b, 0xdc, 0xa1, 0x3f, 0x74, 0x3e, 0x47, 0x8d, 0x00, 0x0a, 0x47, 0x42, 0xdf, 0x76, 0xbd }; char buf[17]; size_t buf_size; ret = gnutls_global_init (); if (ret < 0) fail ("init %d\n", ret); ret = gnutls_x509_crt_init (&cert); if (ret < 0) fail ("crt_init %d\n", ret); ret = gnutls_x509_crt_import (cert, &derCert, GNUTLS_X509_FMT_DER); if (ret < 0) fail ("crt_import %d\n", ret); buf_size = 15; result = gnutls_x509_crt_get_issuer_unique_id (cert, buf, &buf_size); if (result != GNUTLS_E_SHORT_MEMORY_BUFFER) fail ("get_issuer_unique_id short error %d\n", result); if (buf_size != 16) fail ("get_issuer_unique_id buf size %zd\n", buf_size); buf_size = 16; result = gnutls_x509_crt_get_issuer_unique_id (cert, buf, &buf_size); if (result < 0) fail ("get_issuer_unique_id %d\n", result); if (memcmp (buf, expectedId, buf_size) != 0) fail ("expected id mismatch for issuer\n"); buf_size = 15; result = gnutls_x509_crt_get_subject_unique_id (cert, buf, &buf_size); if (result != GNUTLS_E_SHORT_MEMORY_BUFFER) fail ("get_subject_unique_id short error %d\n", result); if (buf_size != 16) fail ("get_subject_unique_id buf size %zd\n", buf_size); buf_size = 16; result = gnutls_x509_crt_get_subject_unique_id (cert, buf, &buf_size); if (result < 0) fail ("get_subject_unique_id %d\n", result); if (memcmp (buf, expectedId, buf_size) != 0) fail ("expected id mismatch for subject\n"); gnutls_x509_crt_deinit (cert); gnutls_global_deinit (); }
/** * gnutls_x509_trust_list_iter_get_ca: * @list: The structure of the list * @iter: A pointer to an iterator (initially the iterator should be %NULL) * @crt: where the certificate will be copied * * This function obtains a certificate in the trust list and advances the * iterator to the next certificate. The certificate returned in @crt must be * deallocated with gnutls_x509_crt_deinit(). * * When past the last element is accessed %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE * is returned and the iterator is reset. * * After use, the iterator must be deinitialized usin * gnutls_x509_trust_list_iter_deinit(). * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 3.4.0 **/ int gnutls_x509_trust_list_iter_get_ca(gnutls_x509_trust_list_t list, gnutls_x509_trust_list_iter_t *iter, gnutls_x509_crt_t *crt) { int ret; /* initialize iterator */ if (*iter == NULL) { *iter = gnutls_malloc(sizeof (struct gnutls_x509_trust_list_iter)); if (*iter == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); (*iter)->node_index = 0; (*iter)->ca_index = 0; #ifdef ENABLE_PKCS11 (*iter)->pkcs11_list = NULL; (*iter)->pkcs11_size = 0; (*iter)->pkcs11_index = 0; #endif /* Advance iterator to the first valid entry */ if (list->node[0].trusted_ca_size == 0) { ret = advance_iter(list, *iter); if (ret != 0) { gnutls_x509_trust_list_iter_deinit(*iter); *iter = NULL; *crt = NULL; return gnutls_assert_val(ret); } } } /* obtain the certificate at the current iterator position */ if ((*iter)->node_index < list->size) { ret = gnutls_x509_crt_init(crt); if (ret < 0) return gnutls_assert_val(ret); ret = _gnutls_x509_crt_cpy(*crt, list->node[(*iter)->node_index].trusted_cas[(*iter)->ca_index]); if (ret < 0) { gnutls_x509_crt_deinit(*crt); return gnutls_assert_val(ret); } } #ifdef ENABLE_PKCS11 else if ( (*iter)->pkcs11_index < (*iter)->pkcs11_size) { ret = gnutls_x509_crt_init(crt); if (ret < 0) return gnutls_assert_val(ret); ret = gnutls_x509_crt_import_pkcs11(*crt, (*iter)->pkcs11_list[(*iter)->pkcs11_index]); if (ret < 0) { gnutls_x509_crt_deinit(*crt); return gnutls_assert_val(ret); } } #endif else { /* iterator is at end */ gnutls_x509_trust_list_iter_deinit(*iter); *iter = NULL; *crt = NULL; return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE); } /* Move iterator to the next position. * GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE is returned if the iterator * has been moved to the end position. That is okay, we return the * certificate that we read and when this function is called again we * report GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE to our caller. */ ret = advance_iter(list, *iter); if (ret < 0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { gnutls_x509_crt_deinit(*crt); *crt = NULL; return gnutls_assert_val(ret); } return 0; }
/* * This function is called after the TCP connect has completed. Setup the TLS * layer and do all necessary magic. */ CURLcode Curl_gtls_connect(struct connectdata *conn, int sockindex) { const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 }; struct SessionHandle *data = conn->data; gnutls_session session; int rc; unsigned int cert_list_size; const gnutls_datum *chainp; unsigned int verify_status; gnutls_x509_crt x509_cert; char certbuf[256]; /* big enough? */ size_t size; unsigned int algo; unsigned int bits; time_t clock; const char *ptr; void *ssl_sessionid; size_t ssl_idsize; /* GnuTLS only supports TLSv1 (and SSLv3?) */ if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) { failf(data, "GnuTLS does not support SSLv2"); return CURLE_SSL_CONNECT_ERROR; } /* allocate a cred struct */ rc = gnutls_certificate_allocate_credentials(&conn->ssl[sockindex].cred); if(rc < 0) { failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc)); return CURLE_SSL_CONNECT_ERROR; } if(data->set.ssl.CAfile) { /* set the trusted CA cert bundle file */ rc = gnutls_certificate_set_x509_trust_file(conn->ssl[sockindex].cred, data->set.ssl.CAfile, GNUTLS_X509_FMT_PEM); if(rc < 0) { infof(data, "error reading ca cert file %s (%s)\n", data->set.ssl.CAfile, gnutls_strerror(rc)); } } /* Initialize TLS session as a client */ rc = gnutls_init(&conn->ssl[sockindex].session, GNUTLS_CLIENT); if(rc) { failf(data, "gnutls_init() failed: %d", rc); return CURLE_SSL_CONNECT_ERROR; } /* convenient assign */ session = conn->ssl[sockindex].session; /* Use default priorities */ rc = gnutls_set_default_priority(session); if(rc < 0) return CURLE_SSL_CONNECT_ERROR; /* Sets the priority on the certificate types supported by gnutls. Priority is higher for types specified before others. After specifying the types you want, you must append a 0. */ rc = gnutls_certificate_type_set_priority(session, cert_type_priority); if(rc < 0) return CURLE_SSL_CONNECT_ERROR; /* put the anonymous credentials to the current session */ rc = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, conn->ssl[sockindex].cred); /* set the connection handle (file descriptor for the socket) */ gnutls_transport_set_ptr(session, (gnutls_transport_ptr)conn->sock[sockindex]); /* This might be a reconnect, so we check for a session ID in the cache to speed up things */ if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, &ssl_idsize)) { /* we got a session id, use it! */ gnutls_session_set_data(session, ssl_sessionid, ssl_idsize); /* Informational message */ infof (data, "SSL re-using session ID\n"); } do { rc = gnutls_handshake(session); if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) { long timeout_ms; long has_passed; if(data->set.timeout || data->set.connecttimeout) { /* get the most strict timeout of the ones converted to milliseconds */ if(data->set.timeout && (data->set.timeout>data->set.connecttimeout)) timeout_ms = data->set.timeout*1000; else timeout_ms = data->set.connecttimeout*1000; } else timeout_ms = DEFAULT_CONNECT_TIMEOUT; /* Evaluate in milliseconds how much time that has passed */ has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle); /* subtract the passed time */ timeout_ms -= has_passed; if(timeout_ms < 0) { /* a precaution, no need to continue if time already is up */ failf(data, "SSL connection timeout"); return CURLE_OPERATION_TIMEOUTED; } rc = Curl_select(conn->sock[sockindex], conn->sock[sockindex], (int)timeout_ms); if(rc > 0) /* reabable or writable, go loop*/ continue; else if(0 == rc) { /* timeout */ failf(data, "SSL connection timeout"); return CURLE_OPERATION_TIMEDOUT; } else { /* anything that gets here is fatally bad */ failf(data, "select on SSL socket, errno: %d", Curl_ourerrno()); return CURLE_SSL_CONNECT_ERROR; } } else break; } while(1); if (rc < 0) { failf(data, "gnutls_handshake() failed: %d", rc); /* gnutls_perror(ret); */ return CURLE_SSL_CONNECT_ERROR; } /* This function will return the peer's raw certificate (chain) as sent by the peer. These certificates are in raw format (DER encoded for X.509). In case of a X.509 then a certificate list may be present. The first certificate in the list is the peer's certificate, following the issuer's certificate, then the issuer's issuer etc. */ chainp = gnutls_certificate_get_peers(session, &cert_list_size); if(!chainp) { if(data->set.ssl.verifyhost) { failf(data, "failed to get server cert"); return CURLE_SSL_PEER_CERTIFICATE; } infof(data, "\t common name: WARNING couldn't obtain\n"); } /* This function will try to verify the peer's certificate and return its status (trusted, invalid etc.). The value of status should be one or more of the gnutls_certificate_status_t enumerated elements bitwise or'd. To avoid denial of service attacks some default upper limits regarding the certificate key size and chain size are set. To override them use gnutls_certificate_set_verify_limits(). */ rc = gnutls_certificate_verify_peers2(session, &verify_status); if (rc < 0) { failf(data, "server cert verify failed: %d", rc); return CURLE_SSL_CONNECT_ERROR; } /* verify_status is a bitmask of gnutls_certificate_status bits */ if(verify_status & GNUTLS_CERT_INVALID) { if (data->set.ssl.verifypeer) { failf(data, "server certificate verification failed. CAfile: %s", data->set.ssl.CAfile?data->set.ssl.CAfile:"none"); return CURLE_SSL_CACERT; } else infof(data, "\t server certificate verification FAILED\n"); } else infof(data, "\t server certificate verification OK\n"); /* initialize an X.509 certificate structure. */ gnutls_x509_crt_init(&x509_cert); /* convert the given DER or PEM encoded Certificate to the native gnutls_x509_crt_t format */ gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER); size=sizeof(certbuf); rc = gnutls_x509_crt_get_dn_by_oid(x509_cert, GNUTLS_OID_X520_COMMON_NAME, 0, /* the first and only one */ FALSE, certbuf, &size); if(rc) { infof(data, "error fetching CN from cert:%s\n", gnutls_strerror(rc)); } /* This function will check if the given certificate's subject matches the given hostname. This is a basic implementation of the matching described in RFC2818 (HTTPS), which takes into account wildcards, and the subject alternative name PKIX extension. Returns non zero on success, and zero on failure. */ rc = gnutls_x509_crt_check_hostname(x509_cert, conn->host.name); if(!rc) { if (data->set.ssl.verifyhost > 1) { failf(data, "SSL: certificate subject name (%s) does not match " "target host name '%s'", certbuf, conn->host.dispname); gnutls_x509_crt_deinit(x509_cert); return CURLE_SSL_PEER_CERTIFICATE; } else infof(data, "\t common name: %s (does not match '%s')\n", certbuf, conn->host.dispname); } else infof(data, "\t common name: %s (matched)\n", certbuf); /* Show: - ciphers used - subject - start date - expire date - common name - issuer */ /* public key algorithm's parameters */ algo = gnutls_x509_crt_get_pk_algorithm(x509_cert, &bits); infof(data, "\t certificate public key: %s\n", gnutls_pk_algorithm_get_name(algo)); /* version of the X.509 certificate. */ infof(data, "\t certificate version: #%d\n", gnutls_x509_crt_get_version(x509_cert)); size = sizeof(certbuf); gnutls_x509_crt_get_dn(x509_cert, certbuf, &size); infof(data, "\t subject: %s\n", certbuf); clock = gnutls_x509_crt_get_activation_time(x509_cert); showtime(data, "start date", clock); clock = gnutls_x509_crt_get_expiration_time(x509_cert); showtime(data, "expire date", clock); size = sizeof(certbuf); gnutls_x509_crt_get_issuer_dn(x509_cert, certbuf, &size); infof(data, "\t issuer: %s\n", certbuf); gnutls_x509_crt_deinit(x509_cert); /* compression algorithm (if any) */ ptr = gnutls_compression_get_name(gnutls_compression_get(session)); /* the *_get_name() says "NULL" if GNUTLS_COMP_NULL is returned */ infof(data, "\t compression: %s\n", ptr); /* the name of the cipher used. ie 3DES. */ ptr = gnutls_cipher_get_name(gnutls_cipher_get(session)); infof(data, "\t cipher: %s\n", ptr); /* the MAC algorithms name. ie SHA1 */ ptr = gnutls_mac_get_name(gnutls_mac_get(session)); infof(data, "\t MAC: %s\n", ptr); if(!ssl_sessionid) { /* this session was not previously in the cache, add it now */ /* get the session ID data size */ gnutls_session_get_data(session, NULL, &ssl_idsize); ssl_sessionid = malloc(ssl_idsize); /* get a buffer for it */ if(ssl_sessionid) { /* extract session ID to the allocated buffer */ gnutls_session_get_data(session, ssl_sessionid, &ssl_idsize); /* store this session id */ return Curl_ssl_addsessionid(conn, ssl_sessionid, ssl_idsize); } } return CURLE_OK; }
int main (int argc, char *argv[]) { gnutls_datum_t ud, tmp; int ret; gnutls_datum_t req; #ifndef NO_LIBCURL CURL *handle; struct curl_slist *headers = NULL; #endif int v, seq; const char *cert_file = argv[1]; const char *issuer_file = argv[2]; const char *signer_file = argv[3]; char *hostname = NULL; gnutls_global_init (); if (argc > 4) hostname = argv[4]; if (hostname == NULL) { gnutls_x509_crt_t cert = load_cert (cert_file); for (seq = 0;; seq++) { ret = gnutls_x509_crt_get_authority_info_access (cert, seq, GNUTLS_IA_OCSP_URI, &tmp, NULL); if (ret == GNUTLS_E_UNKNOWN_ALGORITHM) continue; if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { fprintf (stderr, "No URI was found in the certificate.\n"); exit (1); } if (ret < 0) { fprintf (stderr, "error: %s\n", gnutls_strerror (ret)); exit (1); } printf ("CA issuers URI: %.*s\n", tmp.size, tmp.data); hostname = malloc (tmp.size + 1); memcpy (hostname, tmp.data, tmp.size); hostname[tmp.size] = 0; gnutls_free (tmp.data); break; } gnutls_x509_crt_deinit (cert); } /* Note that the OCSP servers hostname might be available * using gnutls_x509_crt_get_authority_info_access() in the issuer's * certificate */ memset (&ud, 0, sizeof (ud)); fprintf (stderr, "Connecting to %s\n", hostname); _generate_request (&req, cert_file, issuer_file); #ifndef NO_LIBCURL curl_global_init (CURL_GLOBAL_ALL); handle = curl_easy_init (); if (handle == NULL) exit (1); headers = curl_slist_append (headers, "Content-Type: application/ocsp-request"); curl_easy_setopt (handle, CURLOPT_HTTPHEADER, headers); curl_easy_setopt (handle, CURLOPT_POSTFIELDS, (void *) req.data); curl_easy_setopt (handle, CURLOPT_POSTFIELDSIZE, req.size); curl_easy_setopt (handle, CURLOPT_URL, hostname); curl_easy_setopt (handle, CURLOPT_WRITEFUNCTION, get_data); curl_easy_setopt (handle, CURLOPT_WRITEDATA, &ud); ret = curl_easy_perform (handle); if (ret != 0) { fprintf (stderr, "curl[%d] error %d\n", __LINE__, ret); exit (1); } curl_easy_cleanup (handle); #endif _response_info (&ud); v = _verify_response (&ud, signer_file); gnutls_global_deinit (); return v; }
/** * ntfs_pkcs12_extract_rsa_key */ static ntfs_rsa_private_key ntfs_pkcs12_extract_rsa_key(u8 *pfx, int pfx_size, char *password, char *thumbprint, int thumbprint_size, NTFS_DF_TYPES *df_type) { int err, bag_index, flags; gnutls_datum_t dpfx, dkey; gnutls_pkcs12_t pkcs12 = NULL; gnutls_pkcs12_bag_t bag = NULL; gnutls_x509_privkey_t pkey = NULL; gnutls_x509_crt_t crt = NULL; ntfs_rsa_private_key rsa_key = NULL; char purpose_oid[100]; size_t purpose_oid_size = sizeof(purpose_oid); int oid_index; size_t tp_size = thumbprint_size; BOOL have_thumbprint = FALSE; *df_type = DF_TYPE_UNKNOWN; /* Create a pkcs12 structure. */ err = gnutls_pkcs12_init(&pkcs12); if (err) { ntfs_log_error("Failed to initialize PKCS#12 structure: %s\n", gnutls_strerror(err)); return NULL; } /* Convert the PFX file (DER format) to native pkcs12 format. */ dpfx.data = pfx; dpfx.size = pfx_size; err = gnutls_pkcs12_import(pkcs12, &dpfx, GNUTLS_X509_FMT_DER, 0); if (err) { ntfs_log_error("Failed to convert the PFX file from DER to " "native PKCS#12 format: %s\n", gnutls_strerror(err)); goto err; } /* * Verify that the password is correct and that the key file has not * been tampered with. Note if the password has zero length and the * verification fails, retry with password set to NULL. This is needed * to get passwordless .pfx files generated with Windows XP SP1 (and * probably earlier versions of Windows) to work. */ retry_verify: err = gnutls_pkcs12_verify_mac(pkcs12, password); if (err) { if (err == GNUTLS_E_MAC_VERIFY_FAILED && password && !strlen(password)) { password = NULL; goto retry_verify; } ntfs_log_error("Failed to verify the MAC: %s Is the " "password correct?\n", gnutls_strerror(err)); goto err; } for (bag_index = 0; ; bag_index++) { err = gnutls_pkcs12_bag_init(&bag); if (err) { ntfs_log_error("Failed to initialize PKCS#12 Bag " "structure: %s\n", gnutls_strerror(err)); goto err; } err = gnutls_pkcs12_get_bag(pkcs12, bag_index, bag); if (err) { if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { err = 0; break; } ntfs_log_error("Failed to obtain Bag from PKCS#12 " "structure: %s\n", gnutls_strerror(err)); goto err; } check_again: err = gnutls_pkcs12_bag_get_count(bag); if (err < 0) { ntfs_log_error("Failed to obtain Bag count: %s\n", gnutls_strerror(err)); goto err; } err = gnutls_pkcs12_bag_get_type(bag, 0); if (err < 0) { ntfs_log_error("Failed to determine Bag type: %s\n", gnutls_strerror(err)); goto err; } flags = 0; switch (err) { case GNUTLS_BAG_PKCS8_KEY: flags = GNUTLS_PKCS_PLAIN; case GNUTLS_BAG_PKCS8_ENCRYPTED_KEY: err = gnutls_pkcs12_bag_get_data(bag, 0, &dkey); if (err < 0) { ntfs_log_error("Failed to obtain Bag data: " "%s\n", gnutls_strerror(err)); goto err; } err = gnutls_x509_privkey_init(&pkey); if (err) { ntfs_log_error("Failed to initialized " "private key structure: %s\n", gnutls_strerror(err)); goto err; } /* Decrypt the private key into GNU TLS format. */ err = gnutls_x509_privkey_import_pkcs8(pkey, &dkey, GNUTLS_X509_FMT_DER, password, flags); if (err) { ntfs_log_error("Failed to convert private " "key from DER to GNU TLS " "format: %s\n", gnutls_strerror(err)); goto err; } #if 0 /* * Export the key again, but unencrypted, and output it * to stderr. Note the output has an RSA header so to * compare to openssl pkcs12 -nodes -in myfile.pfx * output need to ignore the part of the key between * the first "MII..." up to the second "MII...". The * actual RSA private key begins at the second "MII..." * and in my testing at least was identical to openssl * output and was also identical both on big and little * endian so gnutls should be endianness safe. */ char *buf = malloc(8192); size_t bufsize = 8192; err = gnutls_x509_privkey_export_pkcs8(pkey, GNUTLS_X509_FMT_PEM, "", GNUTLS_PKCS_PLAIN, buf, &bufsize); if (err) { ntfs_log_error("eek1\n"); exit(1); } ntfs_log_error("%s\n", buf); free(buf); #endif /* Convert the private key to our internal format. */ rsa_key = ntfs_rsa_private_key_import_from_gnutls(pkey); if (!rsa_key) goto err; break; case GNUTLS_BAG_ENCRYPTED: err = gnutls_pkcs12_bag_decrypt(bag, password); if (err) { ntfs_log_error("Failed to decrypt Bag: %s\n", gnutls_strerror(err)); goto err; } goto check_again; case GNUTLS_BAG_CERTIFICATE: err = gnutls_pkcs12_bag_get_data(bag, 0, &dkey); if (err < 0) { ntfs_log_error("Failed to obtain Bag data: " "%s\n", gnutls_strerror(err)); goto err; } err = gnutls_x509_crt_init(&crt); if (err) { ntfs_log_error("Failed to initialize " "certificate structure: %s\n", gnutls_strerror(err)); goto err; } err = gnutls_x509_crt_import(crt, &dkey, GNUTLS_X509_FMT_DER); if (err) { ntfs_log_error("Failed to convert certificate " "from DER to GNU TLS format: " "%s\n", gnutls_strerror(err)); goto err; } oid_index = 0; /* * Search in the key purposes for an EFS * encryption purpose or an EFS recovery * purpose, and use the first one found. */ do { purpose_oid_size = sizeof(purpose_oid); err = gnutls_x509_crt_get_key_purpose_oid(crt, oid_index, purpose_oid, &purpose_oid_size, NULL); if (!err) { purpose_oid[purpose_oid_size - 1] = '\0'; if (!strcmp(purpose_oid, NTFS_EFS_CERT_PURPOSE_OID_DRF)) *df_type = DF_TYPE_DRF; else if (!strcmp(purpose_oid, NTFS_EFS_CERT_PURPOSE_OID_DDF)) *df_type = DF_TYPE_DDF; else oid_index++; } } while (!err && (*df_type == DF_TYPE_UNKNOWN)); if (*df_type == DF_TYPE_UNKNOWN) { /* End of list reached ? */ if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) ntfs_log_error("Key does not have an " "EFS purpose OID\n"); else ntfs_log_error("Failed to get a key " "purpose OID : %s ", gnutls_strerror(err)); goto err; } /* Return the thumbprint to the caller. */ err = gnutls_x509_crt_get_fingerprint(crt, GNUTLS_DIG_SHA1, thumbprint, &tp_size); if (err) { ntfs_log_error("Failed to get thumbprint: " "%s\n", gnutls_strerror(err)); goto err; } if (tp_size != NTFS_SHA1_THUMBPRINT_SIZE) { ntfs_log_error("Invalid thumbprint size %zd. " "Should be %d.\n", tp_size, thumbprint_size); err = EINVAL; goto err; } have_thumbprint = TRUE; gnutls_x509_crt_deinit(crt); crt = NULL; break; default: /* We do not care about other types. */ break; } gnutls_pkcs12_bag_deinit(bag); } err: if (rsa_key && (err || *df_type == DF_TYPE_UNKNOWN || !have_thumbprint)) { if (!err) ntfs_log_error("Key type or thumbprint not found, " "aborting.\n"); ntfs_rsa_private_key_release(rsa_key); rsa_key = NULL; } if (crt) gnutls_x509_crt_deinit(crt); if (pkey) gnutls_x509_privkey_deinit(pkey); if (bag) gnutls_pkcs12_bag_deinit(bag); if (pkcs12) gnutls_pkcs12_deinit(pkcs12); return rsa_key; }
void doit (void) { int ret; gnutls_datum_t derCert = { (void*)pem, sizeof (pem) }; gnutls_x509_crt_t cert; size_t data_len = MAX_DATA_SIZE; char data[MAX_DATA_SIZE]; unsigned int critical = 0; int alt_name_count = 0; ret = gnutls_global_init (); if (ret < 0) fail ("init %d\n", ret); ret = gnutls_x509_crt_init (&cert); if (ret < 0) fail ("crt_init %d\n", ret); ret = gnutls_x509_crt_import (cert, &derCert, GNUTLS_X509_FMT_PEM); if (ret < 0) fail ("crt_import %d\n", ret); for (alt_name_count = 0;; ++alt_name_count) { ret = gnutls_x509_crt_get_issuer_alt_name (cert, alt_name_count, data, &data_len, &critical); if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) break; if (ret < 0) fail ("get_issuer_alt_name: %d\n", ret); // TODO: print out / check results if (GNUTLS_SAN_URI == ret) { if (strcmp (data, "http://ca.su.se") != 0) { fail ("unexpected issuer GNUTLS_SAN_URI: %s\n", data); } } else if (GNUTLS_SAN_RFC822NAME == ret) { if (strcmp (data, "*****@*****.**") != 0) { fail ("unexpected issuer GNUTLS_SAN_RFC822NAME: %s\n", data); } } else { fail ("unexpected alt name type: %d\n", ret); } data_len = MAX_DATA_SIZE; } if (alt_name_count != 2) { fail ("unexpected number of alt names: %i\n", alt_name_count); } if (debug) success ("done\n"); gnutls_x509_crt_deinit (cert); gnutls_global_deinit (); }
/* This function will verify the peer's certificate, and check * if the hostname matches, as well as the activation, expiration dates. */ static int verify_certificate_callback(gnutls_session_t session) { unsigned int status; const gnutls_datum_t *cert_list; unsigned int cert_list_size; int ret; gnutls_x509_crt_t cert; const char *hostname; /* read hostname */ hostname = gnutls_session_get_ptr(session); /* This verification function uses the trusted CAs in the credentials * structure. So you must have installed one or more CA certificates. */ ret = gnutls_certificate_verify_peers2(session, &status); if (ret < 0) { logit(LOG_ERR, "Failed verifying certificate peers."); goto error; } if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) logit(LOG_WARNING, "The certificate does not have a known issuer."); if (status & GNUTLS_CERT_REVOKED) logit(LOG_WARNING, "The certificate has been revoked."); if (status & GNUTLS_CERT_EXPIRED) logit(LOG_WARNING, "The certificate has expired."); if (status & GNUTLS_CERT_NOT_ACTIVATED) logit(LOG_WARNING, "The certificate is not yet activated."); if (status & GNUTLS_CERT_INVALID) { logit(LOG_ERR, "The certificate is not trusted."); goto error; } /* Up to here the process is the same for X.509 certificates and * OpenPGP keys. From now on X.509 certificates are assumed. This can * be easily extended to work with openpgp keys as well. */ if (gnutls_certificate_type_get(session) != GNUTLS_CRT_X509) { logit(LOG_ERR, "Not a valid X.509 certificate"); goto error; } if (gnutls_x509_crt_init(&cert) < 0) { logit(LOG_ERR, "Failed init of X.509 cert engine"); goto error; } cert_list = gnutls_certificate_get_peers(session, &cert_list_size); if (cert_list == NULL) { logit(LOG_ERR, "No certificate was found!"); goto error; } if (gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER) < 0) { logit(LOG_ERR, "Error while parsing certificate."); goto error; } if (!gnutls_x509_crt_check_hostname(cert, hostname)) { logit(LOG_ERR, "The certificate's owner does not match the hostname '%s'", hostname); goto error; } gnutls_x509_crt_deinit(cert); /* notify gnutls to continue handshake normally */ logit(LOG_DEBUG, "Certificate OK"); return 0; error: if (secure_ssl) return GNUTLS_E_CERTIFICATE_ERROR; return 0; }
/* Parses a PKCS#12 structure and loads the certificate, private key * and friendly name if possible. Returns zero on success, non-zero * on error. */ static int pkcs12_parse(gnutls_pkcs12 p12, gnutls_x509_privkey *pkey, gnutls_x509_crt *x5, char **friendly_name, const char *password) { gnutls_pkcs12_bag bag = NULL; int i, j, ret = 0; for (i = 0; ret == 0; ++i) { if (bag) gnutls_pkcs12_bag_deinit(bag); ret = gnutls_pkcs12_bag_init(&bag); if (ret < 0) continue; ret = gnutls_pkcs12_get_bag(p12, i, bag); if (ret < 0) continue; gnutls_pkcs12_bag_decrypt(bag, password); for (j = 0; ret == 0 && j < gnutls_pkcs12_bag_get_count(bag); ++j) { gnutls_pkcs12_bag_type type; gnutls_datum data; if (friendly_name && *friendly_name == NULL) { char *name = NULL; gnutls_pkcs12_bag_get_friendly_name(bag, j, &name); if (name) { if (name[0] == '.') name++; /* weird GnuTLS bug? */ *friendly_name = ne_strdup(name); } } type = gnutls_pkcs12_bag_get_type(bag, j); switch (type) { case GNUTLS_BAG_PKCS8_KEY: case GNUTLS_BAG_PKCS8_ENCRYPTED_KEY: /* Ignore any but the first key encountered; really * need to match up keyids. */ if (*pkey) break; gnutls_x509_privkey_init(pkey); ret = gnutls_pkcs12_bag_get_data(bag, j, &data); if (ret < 0) continue; ret = gnutls_x509_privkey_import_pkcs8(*pkey, &data, GNUTLS_X509_FMT_DER, password, 0); if (ret < 0) continue; break; case GNUTLS_BAG_CERTIFICATE: /* Ignore any but the first cert encountered; again, * really need to match up keyids. */ if (*x5) break; ret = gnutls_x509_crt_init(x5); if (ret < 0) continue; ret = gnutls_pkcs12_bag_get_data(bag, j, &data); if (ret < 0) continue; ret = gnutls_x509_crt_import(*x5, &data, GNUTLS_X509_FMT_DER); if (ret < 0) continue; break; default: break; } } } /* Make sure last bag is freed */ if (bag) gnutls_pkcs12_bag_deinit(bag); /* Free in case of error */ if (ret < 0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { if (*x5) gnutls_x509_crt_deinit(*x5); if (*pkey) gnutls_x509_privkey_deinit(*pkey); if (friendly_name && *friendly_name) ne_free(*friendly_name); } if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) ret = 0; return ret; }
static int tds_verify_certificate(gnutls_session_t session) { unsigned int status; int ret; TDSSOCKET *tds = (TDSSOCKET *) gnutls_transport_get_ptr(session); #ifdef ENABLE_DEVELOPING unsigned int list_size; const gnutls_datum_t *cert_list; #endif if (!tds->login) return GNUTLS_E_CERTIFICATE_ERROR; ret = gnutls_certificate_verify_peers2(session, &status); if (ret < 0) { tdsdump_log(TDS_DBG_ERROR, "Error verifying certificate: %s\n", gnutls_strerror(ret)); return GNUTLS_E_CERTIFICATE_ERROR; } #ifdef ENABLE_DEVELOPING cert_list = gnutls_certificate_get_peers(session, &list_size); if (cert_list) { gnutls_x509_crt_t cert; gnutls_datum_t cinfo; char buf[8192]; size_t size; gnutls_x509_crt_init(&cert); gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER); /* This is the preferred way of printing short information about * a certificate. */ size = sizeof(buf); ret = gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_PEM, buf, &size); if (ret == 0) { FILE *f = fopen("cert.dat", "wb"); if (f) { fwrite(buf, size, 1, f); fclose(f); } } ret = gnutls_x509_crt_print(cert, GNUTLS_CRT_PRINT_ONELINE, &cinfo); if (ret == 0) { tdsdump_log(TDS_DBG_INFO1, "Certificate info: %s\n", cinfo.data); gnutls_free(cinfo.data); } gnutls_x509_crt_deinit(cert); } #endif /* Certificate is not trusted */ if (status != 0) { tdsdump_log(TDS_DBG_ERROR, "Certificate status: %u\n", status); return GNUTLS_E_CERTIFICATE_ERROR; } /* check hostname */ if (tds->login->check_ssl_hostname) { const gnutls_datum_t *cert_list; unsigned int list_size; gnutls_x509_crt_t cert; cert_list = gnutls_certificate_get_peers(session, &list_size); if (!cert_list) { tdsdump_log(TDS_DBG_ERROR, "Error getting TLS session peers\n"); return GNUTLS_E_CERTIFICATE_ERROR; } gnutls_x509_crt_init(&cert); gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER); ret = gnutls_x509_crt_check_hostname(cert, tds_dstr_cstr(&tds->login->server_host_name)); gnutls_x509_crt_deinit(cert); if (!ret) { tdsdump_log(TDS_DBG_ERROR, "Certificate hostname does not match\n"); return GNUTLS_E_CERTIFICATE_ERROR; } } /* notify gnutls to continue handshake normally */ return 0; }
void doit(void) { char buf[128]; int ret; const char *lib, *bin; gnutls_x509_crt_t crt; gnutls_x509_privkey_t key; gnutls_datum_t tmp, sig; gnutls_privkey_t pkey; gnutls_pubkey_t pubkey; gnutls_pubkey_t pubkey2; unsigned i, sigalgo; bin = softhsm_bin(); lib = softhsm_lib(); ret = global_init(); if (ret != 0) { fail("%d: %s\n", ret, gnutls_strerror(ret)); } gnutls_pkcs11_set_pin_function(pin_func, NULL); gnutls_global_set_log_function(tls_log_func); if (debug) gnutls_global_set_log_level(4711); set_softhsm_conf(CONFIG); snprintf(buf, sizeof(buf), "%s --init-token --slot 0 --label test --so-pin " PIN " --pin " PIN, bin); system(buf); ret = gnutls_pkcs11_add_provider(lib, NULL); if (ret < 0) { fail("gnutls_x509_crt_init: %s\n", gnutls_strerror(ret)); } if (verify_eddsa_presence() == 0) { fprintf(stderr, "Skipping test as no EDDSA mech is supported\n"); exit(77); } ret = gnutls_x509_crt_init(&crt); if (ret < 0) fail("gnutls_x509_crt_init: %s\n", gnutls_strerror(ret)); ret = gnutls_x509_crt_import(crt, &server_ca3_eddsa_cert, GNUTLS_X509_FMT_PEM); if (ret < 0) fail("gnutls_x509_crt_import: %s\n", gnutls_strerror(ret)); if (debug) { gnutls_x509_crt_print(crt, GNUTLS_CRT_PRINT_ONELINE, &tmp); printf("\tCertificate: %.*s\n", tmp.size, tmp.data); gnutls_free(tmp.data); } ret = gnutls_x509_privkey_init(&key); if (ret < 0) { fail("gnutls_x509_privkey_init: %s\n", gnutls_strerror(ret)); } ret = gnutls_x509_privkey_import(key, &server_ca3_eddsa_key, GNUTLS_X509_FMT_PEM); if (ret < 0) { fail("gnutls_x509_privkey_import: %s\n", gnutls_strerror(ret)); } /* initialize softhsm token */ ret = gnutls_pkcs11_token_init(SOFTHSM_URL, PIN, "test"); if (ret < 0) { fail("gnutls_pkcs11_token_init: %s\n", gnutls_strerror(ret)); } ret = gnutls_pkcs11_token_set_pin(SOFTHSM_URL, NULL, PIN, GNUTLS_PIN_USER); if (ret < 0) { fail("gnutls_pkcs11_token_set_pin: %s\n", gnutls_strerror(ret)); } ret = gnutls_pkcs11_copy_x509_crt(SOFTHSM_URL, crt, "cert", GNUTLS_PKCS11_OBJ_FLAG_MARK_PRIVATE | GNUTLS_PKCS11_OBJ_FLAG_LOGIN); if (ret < 0) { fail("gnutls_pkcs11_copy_x509_crt: %s\n", gnutls_strerror(ret)); } ret = gnutls_pkcs11_copy_x509_privkey(SOFTHSM_URL, key, "cert", GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, GNUTLS_PKCS11_OBJ_FLAG_MARK_PRIVATE | GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE | GNUTLS_PKCS11_OBJ_FLAG_LOGIN); if (ret < 0) { fail("gnutls_pkcs11_copy_x509_privkey: %s\n", gnutls_strerror(ret)); } gnutls_x509_crt_deinit(crt); gnutls_x509_privkey_deinit(key); gnutls_pkcs11_set_pin_function(NULL, NULL); assert(gnutls_privkey_init(&pkey) == 0); ret = gnutls_privkey_import_pkcs11_url(pkey, SOFTHSM_URL ";object=cert;object-type=private;pin-value=" PIN); if (ret < 0) { fail("error in gnutls_privkey_import_pkcs11_url: %s\n", gnutls_strerror(ret)); } assert(gnutls_pubkey_init(&pubkey) == 0); assert(gnutls_pubkey_import_privkey(pubkey, pkey, 0, 0) == 0); assert(gnutls_pubkey_init(&pubkey2) == 0); assert(gnutls_pubkey_import_x509_raw (pubkey2, &server_ca3_eddsa_cert, GNUTLS_X509_FMT_PEM, 0) == 0); /* this is the algorithm supported by the certificate */ sigalgo = GNUTLS_SIGN_EDDSA_ED25519; for (i = 0; i < 20; i++) { /* check whether privkey and pubkey are operational * by signing and verifying */ ret = gnutls_privkey_sign_data2(pkey, sigalgo, 0, &testdata, &sig); if (ret < 0) myfail("Error signing data %s\n", gnutls_strerror(ret)); /* verify against the pubkey in PKCS #11 */ ret = gnutls_pubkey_verify_data2(pubkey, sigalgo, 0, &testdata, &sig); if (ret < 0) myfail("Error verifying data1: %s\n", gnutls_strerror(ret)); /* verify against the raw pubkey */ ret = gnutls_pubkey_verify_data2(pubkey2, sigalgo, 0, &testdata, &sig); if (ret < 0) myfail("Error verifying data2: %s\n", gnutls_strerror(ret)); gnutls_free(sig.data); } gnutls_pubkey_deinit(pubkey2); gnutls_pubkey_deinit(pubkey); gnutls_privkey_deinit(pkey); gnutls_global_deinit(); remove(CONFIG); }
std::shared_ptr<security::cert::certificateChain> TLSSocket::getPeerCertificates() const { unsigned int certCount = 0; const gnutls_datum* rawData = gnutls_certificate_get_peers (*m_session->m_gnutlsSession, &certCount); if (rawData == NULL) return NULL; // Try X.509 gnutls_x509_crt* x509Certs = new gnutls_x509_crt[certCount]; for (unsigned int i = 0; i < certCount; ++i) { gnutls_x509_crt_init(x509Certs + i); int res = gnutls_x509_crt_import(x509Certs[i], rawData + i, GNUTLS_X509_FMT_DER); if (res < 0) { // XXX more fine-grained error reporting? delete [] x509Certs; return NULL; } } { std::vector <std::shared_ptr<security::cert::certificate> > certs; bool error = false; for (unsigned int i = 0 ; i < certCount ; ++i) { size_t dataSize = 0; gnutls_x509_crt_export(x509Certs[i], GNUTLS_X509_FMT_DER, NULL, &dataSize); std::vector <byte_t> data(dataSize); gnutls_x509_crt_export(x509Certs[i], GNUTLS_X509_FMT_DER, &data[0], &dataSize); std::shared_ptr<security::cert::X509Certificate> cert = security::cert::X509Certificate::import(&data[0], dataSize); if (cert != NULL) certs.push_back(cert); else error = true; gnutls_x509_crt_deinit(x509Certs[i]); } delete [] x509Certs; if (error) return NULL; return vmime::factory<security::cert::certificateChain>::create(certs); } delete [] x509Certs; return NULL; }
bool CTlsSocket::ExtractCert(gnutls_datum_t const* datum, CCertificate& out) { gnutls_x509_crt_t cert; if (gnutls_x509_crt_init(&cert)) { m_pOwner->LogMessage(MessageType::Error, _("Could not initialize structure for peer certificates, gnutls_x509_crt_init failed")); return false; } if (gnutls_x509_crt_import(cert, datum, GNUTLS_X509_FMT_DER)) { m_pOwner->LogMessage(MessageType::Error, _("Could not import peer certificates, gnutls_x509_crt_import failed")); gnutls_x509_crt_deinit(cert); return false; } wxDateTime expirationTime = gnutls_x509_crt_get_expiration_time(cert); wxDateTime activationTime = gnutls_x509_crt_get_activation_time(cert); // Get the serial number of the certificate unsigned char buffer[40]; size_t size = sizeof(buffer); int res = gnutls_x509_crt_get_serial(cert, buffer, &size); if( res != 0 ) { size = 0; } wxString serial = bin2hex(buffer, size); unsigned int pkBits; int pkAlgo = gnutls_x509_crt_get_pk_algorithm(cert, &pkBits); wxString pkAlgoName; if (pkAlgo >= 0) { const char* pAlgo = gnutls_pk_algorithm_get_name((gnutls_pk_algorithm_t)pkAlgo); if (pAlgo) pkAlgoName = wxString(pAlgo, wxConvUTF8); } int signAlgo = gnutls_x509_crt_get_signature_algorithm(cert); wxString signAlgoName; if (signAlgo >= 0) { const char* pAlgo = gnutls_sign_algorithm_get_name((gnutls_sign_algorithm_t)signAlgo); if (pAlgo) signAlgoName = wxString(pAlgo, wxConvUTF8); } wxString subject, issuer; size = 0; res = gnutls_x509_crt_get_dn(cert, 0, &size); if (size) { char* dn = new char[size + 1]; dn[size] = 0; if (!(res = gnutls_x509_crt_get_dn(cert, dn, &size))) { dn[size] = 0; subject = wxString(dn, wxConvUTF8); } else LogError(res, _T("gnutls_x509_crt_get_dn")); delete [] dn; } else LogError(res, _T("gnutls_x509_crt_get_dn")); if (subject.empty()) { m_pOwner->LogMessage(MessageType::Error, _("Could not get distinguished name of certificate subject, gnutls_x509_get_dn failed")); gnutls_x509_crt_deinit(cert); return false; } std::vector<wxString> alt_subject_names = GetCertSubjectAltNames(cert); size = 0; res = gnutls_x509_crt_get_issuer_dn(cert, 0, &size); if (size) { char* dn = new char[++size + 1]; dn[size] = 0; if (!(res = gnutls_x509_crt_get_issuer_dn(cert, dn, &size))) { dn[size] = 0; issuer = wxString(dn, wxConvUTF8); } else LogError(res, _T("gnutls_x509_crt_get_issuer_dn")); delete [] dn; } else LogError(res, _T("gnutls_x509_crt_get_issuer_dn")); if (issuer.empty() ) { m_pOwner->LogMessage(MessageType::Error, _("Could not get distinguished name of certificate issuer, gnutls_x509_get_issuer_dn failed")); gnutls_x509_crt_deinit(cert); return false; } wxString fingerprint_sha256; wxString fingerprint_sha1; unsigned char digest[100]; size = sizeof(digest) - 1; if (!gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA256, digest, &size)) { digest[size] = 0; fingerprint_sha256 = bin2hex(digest, size); } size = sizeof(digest) - 1; if (!gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA1, digest, &size)) { digest[size] = 0; fingerprint_sha1 = bin2hex(digest, size); } gnutls_x509_crt_deinit(cert); out = CCertificate( datum->data, datum->size, activationTime, expirationTime, serial, pkAlgoName, pkBits, signAlgoName, fingerprint_sha256, fingerprint_sha1, issuer, subject, alt_subject_names); return true; }
~X509CertList() { for (std::vector<gnutls_x509_crt_t>::iterator i = certs.begin(); i != certs.end(); ++i) gnutls_x509_crt_deinit(*i); }
int CTlsSocket::VerifyCertificate() { if (m_tlsState != handshake) { m_pOwner->LogMessage(::Debug_Warning, _T("VerifyCertificate called at wrong time")); return FZ_REPLY_ERROR; } m_tlsState = verifycert; if (gnutls_certificate_type_get(m_session) != GNUTLS_CRT_X509) { m_pOwner->LogMessage(::Error, _("Unsupported certificate type")); Failure(0, ECONNABORTED); return FZ_REPLY_ERROR; } unsigned int status = 0; if (gnutls_certificate_verify_peers2(m_session, &status) < 0) { m_pOwner->LogMessage(::Error, _("Failed to verify peer certificate")); Failure(0, ECONNABORTED); return FZ_REPLY_ERROR; } if (status & GNUTLS_CERT_REVOKED) { m_pOwner->LogMessage(::Error, _("Beware! Certificate has been revoked")); Failure(0, ECONNABORTED); return FZ_REPLY_ERROR; } if (status & GNUTLS_CERT_SIGNER_NOT_CA) { m_pOwner->LogMessage(::Error, _("Incomplete chain, top certificate is not self-signed certificate authority certificate")); Failure(0, ECONNABORTED); return FZ_REPLY_ERROR; } if (m_require_root_trust && status & GNUTLS_CERT_SIGNER_NOT_FOUND) { m_pOwner->LogMessage(::Error, _("Root certificate is not trusted")); Failure(0, ECONNABORTED); return FZ_REPLY_ERROR; } unsigned int cert_list_size; const gnutls_datum_t* cert_list = gnutls_certificate_get_peers(m_session, &cert_list_size); if (!cert_list || !cert_list_size) { m_pOwner->LogMessage(::Error, _("gnutls_certificate_get_peers returned no certificates")); Failure(0, ECONNABORTED); return FZ_REPLY_ERROR; } if (m_implicitTrustedCert.data) { if (m_implicitTrustedCert.size != cert_list[0].size || memcmp(m_implicitTrustedCert.data, cert_list[0].data, cert_list[0].size)) { m_pOwner->LogMessage(::Error, _("Primary connection and data connection certificates don't match.")); Failure(0, ECONNABORTED); return FZ_REPLY_ERROR; } TrustCurrentCert(true); if (m_tlsState != conn) return FZ_REPLY_ERROR; return FZ_REPLY_OK; } std::vector<CCertificate> certificates; for (unsigned int i = 0; i < cert_list_size; i++) { gnutls_x509_crt_t cert; if (gnutls_x509_crt_init(&cert)) { m_pOwner->LogMessage(::Error, _("Could not initialize structure for peer certificates, gnutls_x509_crt_init failed")); Failure(0, ECONNABORTED); return FZ_REPLY_ERROR; } if (gnutls_x509_crt_import(cert, cert_list, GNUTLS_X509_FMT_DER)) { m_pOwner->LogMessage(::Error, _("Could not import peer certificates, gnutls_x509_crt_import failed")); Failure(0, ECONNABORTED); gnutls_x509_crt_deinit(cert); return FZ_REPLY_ERROR; } wxDateTime expirationTime = gnutls_x509_crt_get_expiration_time(cert); wxDateTime activationTime = gnutls_x509_crt_get_activation_time(cert); // Get the serial number of the certificate unsigned char buffer[40]; size_t size = sizeof(buffer); int res = gnutls_x509_crt_get_serial(cert, buffer, &size); wxString serial = bin2hex(buffer, size); unsigned int bits; int algo = gnutls_x509_crt_get_pk_algorithm(cert, &bits); wxString algoName; const char* pAlgo = gnutls_pk_algorithm_get_name((gnutls_pk_algorithm_t)algo); if (pAlgo) algoName = wxString(pAlgo, wxConvUTF8); //int version = gnutls_x509_crt_get_version(cert); wxString subject, issuer; size = 0; res = gnutls_x509_crt_get_dn(cert, 0, &size); if (size) { char* dn = new char[size + 1]; dn[size] = 0; if (!(res = gnutls_x509_crt_get_dn(cert, dn, &size))) { dn[size] = 0; subject = wxString(dn, wxConvUTF8); } else LogError(res); delete [] dn; } else LogError(res); if (subject == _T("")) { m_pOwner->LogMessage(::Error, _("Could not get distinguished name of certificate subject, gnutls_x509_get_dn failed")); Failure(0, ECONNABORTED); gnutls_x509_crt_deinit(cert); return FZ_REPLY_ERROR; } size = 0; res = gnutls_x509_crt_get_issuer_dn(cert, 0, &size); if (size) { char* dn = new char[++size + 1]; dn[size] = 0; if (!(res = gnutls_x509_crt_get_issuer_dn(cert, dn, &size))) { dn[size] = 0; issuer = wxString(dn, wxConvUTF8); } else LogError(res); delete [] dn; } else LogError(res); if (issuer == _T("")) { m_pOwner->LogMessage(::Error, _("Could not get distinguished name of certificate issuer, gnutls_x509_get_issuer_dn failed")); Failure(0, ECONNABORTED); gnutls_x509_crt_deinit(cert); return FZ_REPLY_ERROR; } wxString fingerprint_md5; wxString fingerprint_sha1; unsigned char digest[100]; size = sizeof(digest) - 1; if (!gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_MD5, digest, &size)) { digest[size] = 0; fingerprint_md5 = bin2hex(digest, size); } size = sizeof(digest) - 1; if (!gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA1, digest, &size)) { digest[size] = 0; fingerprint_sha1 = bin2hex(digest, size); } certificates.push_back(CCertificate( cert_list->data, cert_list->size, activationTime, expirationTime, serial, algoName, bits, fingerprint_md5, fingerprint_sha1, subject, issuer)); cert_list++; } CCertificateNotification *pNotification = new CCertificateNotification( m_pOwner->GetCurrentServer()->GetHost(), m_pOwner->GetCurrentServer()->GetPort(), GetCipherName(), GetMacName(), certificates); m_pOwner->SendAsyncRequest(pNotification); m_pOwner->LogMessage(Status, _("Verifying certificate...")); return FZ_REPLY_WOULDBLOCK; }
void doit(void) { gnutls_certificate_credentials_t x509_cred; int ret; unsigned int i; gnutls_x509_crt_t issuer; gnutls_x509_crt_t list[LIST_SIZE]; char dn[128]; size_t dn_size; unsigned int list_size; /* this must be called once in the program */ global_init(); gnutls_global_set_log_function(tls_log_func); if (debug) gnutls_global_set_log_level(6); gnutls_certificate_allocate_credentials(&x509_cred); gnutls_certificate_set_x509_trust_mem(x509_cred, &ca, GNUTLS_X509_FMT_PEM); gnutls_certificate_set_x509_key_mem(x509_cred, &server_cert, &server_key, GNUTLS_X509_FMT_PEM); /* test for gnutls_certificate_get_issuer() */ list_size = LIST_SIZE; ret = gnutls_x509_crt_list_import(list, &list_size, &cert, GNUTLS_X509_FMT_PEM, GNUTLS_X509_CRT_LIST_FAIL_IF_UNSORTED); if (ret < 0) fail("gnutls_x509_crt_list_import"); ret = gnutls_certificate_get_issuer(x509_cred, list[0], &issuer, 0); if (ret < 0) fail("gnutls_certificate_get_isser"); ret = gnutls_certificate_get_issuer(x509_cred, list[0], &issuer, GNUTLS_TL_GET_COPY); if (ret < 0) fail("gnutls_certificate_get_isser"); dn_size = sizeof(dn); ret = gnutls_x509_crt_get_dn(issuer, dn, &dn_size); if (ret < 0) fail("gnutls_certificate_get_isser"); gnutls_x509_crt_deinit(issuer); if (debug) fprintf(stderr, "Issuer's DN: %s\n", dn); for (i = 0; i < list_size; i++) gnutls_x509_crt_deinit(list[i]); gnutls_certificate_free_credentials(x509_cred); gnutls_global_deinit(); if (debug) success("success"); }
static int my_verify_callback(gnutls_session_t ssl) { unsigned int status; const gnutls_datum_t *cert_list; unsigned int cert_list_size; int ret; MYSQL *mysql= (MYSQL *)gnutls_session_get_ptr(ssl); MARIADB_PVIO *pvio= mysql->net.pvio; gnutls_x509_crt_t cert; const char *hostname; /* read hostname */ hostname = mysql->host; /* skip verification if no ca_file/path was specified */ if (!mysql->options.ssl_ca) return 0; /* This verification function uses the trusted CAs in the credentials * structure. So you must have installed one or more CA certificates. */ ret = gnutls_certificate_verify_peers2 (ssl, &status); if (ret < 0) { pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "CA verification failed"); return GNUTLS_E_CERTIFICATE_ERROR; } // mysql->net.vio->status= status; if (status & GNUTLS_CERT_INVALID) { return GNUTLS_E_CERTIFICATE_ERROR; } /* Up to here the process is the same for X.509 certificates and * OpenPGP keys. From now on X.509 certificates are assumed. This can * be easily extended to work with openpgp keys as well. */ if (gnutls_certificate_type_get (ssl) != GNUTLS_CRT_X509) { pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Expected X509 certificate"); return GNUTLS_E_CERTIFICATE_ERROR; } if (gnutls_x509_crt_init (&cert) < 0) { pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Error during certificate initialization"); return GNUTLS_E_CERTIFICATE_ERROR; } cert_list = gnutls_certificate_get_peers (ssl, &cert_list_size); if (cert_list == NULL) { gnutls_x509_crt_deinit (cert); pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "No certificate found"); return GNUTLS_E_CERTIFICATE_ERROR; } if (gnutls_x509_crt_import (cert, &cert_list[0], GNUTLS_X509_FMT_DER) < 0) { gnutls_x509_crt_deinit (cert); pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Unknown SSL error"); return GNUTLS_E_CERTIFICATE_ERROR; } if ((mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT) && !gnutls_x509_crt_check_hostname (cert, hostname)) { gnutls_x509_crt_deinit (cert); pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Hostname in certificate doesn't match"); return GNUTLS_E_CERTIFICATE_ERROR; } gnutls_x509_crt_deinit (cert); /* notify gnutls to continue handshake normally */ CLEAR_CLIENT_ERROR(mysql); return 0; }