static gboolean x509_compare_pubkeys (PurpleCertificate *crt1, PurpleCertificate *crt2) { gnutls_x509_crt_t crt_dat1, crt_dat2; unsigned char buffer1[64], buffer2[64]; size_t size1, size2; size1 = size2 = sizeof(buffer1); g_return_val_if_fail(crt1 && crt2, FALSE); g_return_val_if_fail(crt1->scheme == &x509_gnutls, FALSE); g_return_val_if_fail(crt2->scheme == &x509_gnutls, FALSE); crt_dat1 = X509_GET_GNUTLS_DATA(crt1); if (gnutls_x509_crt_get_key_id(crt_dat1, KEYID_FLAG, buffer1, &size1) != 0) { return FALSE; } crt_dat2 = X509_GET_GNUTLS_DATA(crt2); if (gnutls_x509_crt_get_key_id(crt_dat2, KEYID_FLAG, buffer2, &size2) != 0) { return FALSE; } if (size1 != size2) { return FALSE; } return memcmp(buffer1, buffer2, size1) == 0; }
/*! Adds the authority key identifier extension to the certificate. The key is extracted the specified certificate which must be the one later used to sign the certificate. */ bool CertificateBuilder::addAuthorityKeyIdentifier(const QSslCertificate &qcacert) { gnutls_x509_crt_t cacrt = qsslcert_to_crt(qcacert, &d->errnumber); if (GNUTLS_E_SUCCESS != d->errnumber) return false; QByteArray ba(128, 0); // Normally 20 bytes (SHA1) size_t size = ba.size(); // Try using the subject keyid d->errnumber = gnutls_x509_crt_get_subject_key_id(cacrt, reinterpret_cast<unsigned char *>(ba.data()), &size, NULL); // Or fallback to creating it if (GNUTLS_E_SUCCESS != d->errnumber) { d->errnumber = gnutls_x509_crt_get_key_id(cacrt, 0, reinterpret_cast<unsigned char *>(ba.data()), &size); if (GNUTLS_E_SUCCESS != d->errnumber) { gnutls_x509_crt_deinit(cacrt); return false; } } gnutls_x509_crt_deinit(cacrt); d->errnumber = gnutls_x509_crt_set_authority_key_id(d->crt, reinterpret_cast<const unsigned char *>(ba.constData()), size); return GNUTLS_E_SUCCESS == d->errnumber; }
InfoHash Certificate::getId() const { if (not cert) return {}; InfoHash id; size_t sz = id.size(); if (gnutls_x509_crt_get_key_id(cert, 0, id.data(), &sz) != GNUTLS_E_SUCCESS || sz != id.size()) throw CryptoException("Can't get certificate public key ID."); return id; }
static gnutls_x509_crt generate_certificate(requiem_client_profile_t *cp, gnutls_x509_privkey key, int expire) { int ret; char buf[1024]; gnutls_x509_crt crt; uint64_t analyzerid; size_t size = sizeof(buf); ret = gnutls_x509_crt_init(&crt); if ( ret < 0 ) { fprintf(stderr, "error creating x509 certificate: %s.\n", gnutls_strerror(ret)); return NULL; } if ( ! expire ) expire = 0x7fffffff; else expire = time(NULL) + expire * 24 * 60 * 60; gnutls_x509_crt_set_version(crt, 3); gnutls_x509_crt_set_ca_status(crt, 0); gnutls_x509_crt_set_activation_time(crt, time(NULL)); gnutls_x509_crt_set_expiration_time(crt, expire); analyzerid = requiem_client_profile_get_analyzerid(cp); ret = snprintf(buf, sizeof(buf), "%" REQUIEM_PRIu64, analyzerid); ret = gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_DN_QUALIFIER, 0, buf, ret); if ( ret < 0 ) { fprintf(stderr, "error setting common name: %s.\n", gnutls_strerror(ret)); return NULL; } gnutls_x509_crt_set_serial(crt, &analyzerid, sizeof(analyzerid)); if ( ! key ) return crt; gnutls_x509_crt_set_key(crt, key); ret = gnutls_x509_crt_get_key_id(crt, 0, (unsigned char *) buf, &size); if ( ret == 0 ) { ret = gnutls_x509_crt_set_subject_key_id(crt, buf, size); if ( ret < 0 ) { gnutls_x509_crt_deinit(crt); fprintf(stderr, "error setting subject key ID: %s\n", gnutls_strerror(ret)); return NULL; } } return crt; }
/*! Adds the subject key identifier extension to the certificate. The key is extracted automatically from the certificate being created. */ bool CertificateBuilder::addSubjectKeyIdentifier() { QByteArray ba(128, 0); // Normally 20 bytes (SHA1) size_t size = ba.size(); d->errnumber = gnutls_x509_crt_get_key_id(d->crt, 0, reinterpret_cast<unsigned char *>(ba.data()), &size); if (GNUTLS_E_SUCCESS != d->errnumber) return false; d->errnumber = gnutls_x509_crt_set_subject_key_id (d->crt, ba.constData(), size); return GNUTLS_E_SUCCESS == d->errnumber; }
static gnutls_x509_crt generate_signed_certificate(requiem_client_profile_t *cp, uint64_t analyzerid, gnutls_x509_crt ca_crt, gnutls_x509_privkey ca_key, gnutls_x509_crq crq) { int ret; gnutls_x509_crt crt; unsigned char buf[65535]; size_t size = sizeof(buf); crt = generate_certificate(cp, NULL, generated_certificate_lifetime); if ( ! crt ) return NULL; ret = gnutls_x509_crt_set_crq(crt, crq); if ( ret < 0 ) { fprintf(stderr, "error associating certificate with CRQ: %s.\n", gnutls_strerror(ret)); goto err; } ret = gnutls_x509_crt_set_serial(crt, &analyzerid, sizeof(analyzerid)); if ( ret < 0 ) { fprintf(stderr, "error setting certificate serial: %s.\n", gnutls_strerror(ret)); goto err; } ret = gnutls_x509_crt_get_key_id(ca_crt, 0, buf, &size); if ( ret < 0 ) { fprintf(stderr, "error getting CA key ID: %s.\n", gnutls_strerror(ret)); goto err; } ret = gnutls_x509_crt_set_authority_key_id(crt, buf, size); if ( ret < 0 ) { fprintf(stderr, "error setting authority key ID: %s?\n", gnutls_strerror(ret)); goto err; } ret = gnutls_x509_crt_sign(crt, ca_crt, ca_key); if ( ret < 0 ) { fprintf(stderr, "error signing certificate: %s.\n", gnutls_strerror(ret)); goto err; } return crt; err: gnutls_x509_crt_deinit(crt); return NULL; }
QString Cert::sha1_hash() { if (imported == false) { return ""; } unsigned char id[32]; size_t len = sizeof(id); int ret = gnutls_x509_crt_get_key_id(this->crt, 0, id, &len); if (ret < 0) { this->last_err = gnutls_strerror(ret); return ""; } QByteArray array; array.append((const char*)id, len); QByteArray hex = array.toHex(); QString s = QObject::tr("SHA1:") + hex; return s; }
/** * gnutls_pkcs11_copy_x509_crt: * @token_url: A PKCS #11 URL specifying a token * @crt: A certificate * @label: A name to be used for the stored data * @flags: One of GNUTLS_PKCS11_OBJ_FLAG_* * * This function will copy a certificate into a PKCS #11 token specified by * a URL. The certificate can be marked as trusted or not. * * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a * negative error value. **/ int gnutls_pkcs11_copy_x509_crt (const char *token_url, gnutls_x509_crt_t crt, const char *label, unsigned int flags) { int ret; pakchois_session_t *pks; struct pkcs11_url_info info; ck_rv_t rv; size_t der_size, id_size; opaque *der = NULL; opaque id[20]; struct ck_attribute a[8]; ck_object_class_t class = CKO_CERTIFICATE; ck_certificate_type_t type = CKC_X_509; ck_object_handle_t obj; unsigned int tval = 1; int a_val; ret = pkcs11_url_to_info (token_url, &info); if (ret < 0) { gnutls_assert (); return ret; } ret = pkcs11_open_session (&pks, &info, SESSION_WRITE | pkcs11_obj_flags_to_int (flags)); if (ret < 0) { gnutls_assert (); return ret; } ret = gnutls_x509_crt_export (crt, GNUTLS_X509_FMT_DER, NULL, &der_size); if (ret < 0 && ret != GNUTLS_E_SHORT_MEMORY_BUFFER) { gnutls_assert (); goto cleanup; } der = gnutls_malloc (der_size); if (der == NULL) { gnutls_assert (); ret = GNUTLS_E_MEMORY_ERROR; goto cleanup; } ret = gnutls_x509_crt_export (crt, GNUTLS_X509_FMT_DER, der, &der_size); if (ret < 0) { gnutls_assert (); goto cleanup; } id_size = sizeof (id); ret = gnutls_x509_crt_get_key_id (crt, 0, id, &id_size); if (ret < 0) { gnutls_assert (); goto cleanup; } /* FIXME: copy key usage flags */ a[0].type = CKA_CLASS; a[0].value = &class; a[0].value_len = sizeof (class); a[1].type = CKA_ID; a[1].value = id; a[1].value_len = id_size; a[2].type = CKA_VALUE; a[2].value = der; a[2].value_len = der_size; a[3].type = CKA_TOKEN; a[3].value = &tval; a[3].value_len = sizeof (tval); a[4].type = CKA_CERTIFICATE_TYPE; a[4].value = &type; a[4].value_len = sizeof (type); a_val = 5; if (label) { a[a_val].type = CKA_LABEL; a[a_val].value = (void *) label; a[a_val].value_len = strlen (label); a_val++; } if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_TRUSTED) { a[a_val].type = CKA_TRUSTED; a[a_val].value = &tval; a[a_val].value_len = sizeof (tval); a_val++; } rv = pakchois_create_object (pks, a, a_val, &obj); if (rv != CKR_OK) { gnutls_assert (); _gnutls_debug_log ("pkcs11: %s\n", pakchois_error (rv)); ret = pkcs11_rv_to_err (rv); goto cleanup; } /* generated! */ ret = 0; cleanup: gnutls_free (der); pakchois_close_session (pks); return ret; }
/** * gnutls_pkcs11_copy_x509_crt2: * @token_url: A PKCS #11 URL specifying a token * @crt: The certificate to copy * @label: The name to be used for the stored data * @cid: The CKA_ID to set for the object -if NULL, the ID will be derived from the public key * @flags: One of GNUTLS_PKCS11_OBJ_FLAG_* * * This function will copy a certificate into a PKCS #11 token specified by * a URL. Valid flags to mark the certificate: %GNUTLS_PKCS11_OBJ_FLAG_MARK_TRUSTED, * %GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE, %GNUTLS_PKCS11_OBJ_FLAG_MARK_PRIVATE, * %GNUTLS_PKCS11_OBJ_FLAG_MARK_CA, %GNUTLS_PKCS11_OBJ_FLAG_MARK_ALWAYS_AUTH. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 3.4.0 **/ int gnutls_pkcs11_copy_x509_crt2(const char *token_url, gnutls_x509_crt_t crt, const char *label, const gnutls_datum_t *cid, unsigned int flags) { int ret; struct p11_kit_uri *info = NULL; ck_rv_t rv; size_t der_size, id_size, serial_size; gnutls_datum_t serial_der = {NULL, 0}; uint8_t *der = NULL; uint8_t serial[128]; uint8_t id[20]; struct ck_attribute a[MAX_ASIZE]; ck_object_class_t class = CKO_CERTIFICATE; ck_certificate_type_t type = CKC_X_509; ck_object_handle_t ctx; unsigned a_val; struct pkcs11_session_info sinfo; PKCS11_CHECK_INIT; ret = pkcs11_url_to_info(token_url, &info, 0); if (ret < 0) { gnutls_assert(); return ret; } ret = pkcs11_open_session(&sinfo, NULL, info, SESSION_WRITE | pkcs11_obj_flags_to_int(flags)); p11_kit_uri_free(info); if (ret < 0) { gnutls_assert(); return ret; } der_size = 0; ret = gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_DER, NULL, &der_size); if (ret < 0 && ret != GNUTLS_E_SHORT_MEMORY_BUFFER) { gnutls_assert(); goto cleanup; } der = gnutls_malloc(der_size); if (der == NULL) { gnutls_assert(); ret = GNUTLS_E_MEMORY_ERROR; goto cleanup; } ret = gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_DER, der, &der_size); if (ret < 0) { gnutls_assert(); goto cleanup; } a[0].type = CKA_CLASS; a[0].value = &class; a[0].value_len = sizeof(class); a[1].type = CKA_ID; if (cid == NULL || cid->size == 0) { id_size = sizeof(id); ret = gnutls_x509_crt_get_subject_key_id(crt, id, &id_size, NULL); if (ret < 0) { id_size = sizeof(id); ret = gnutls_x509_crt_get_key_id(crt, 0, id, &id_size); if (ret < 0) { gnutls_assert(); goto cleanup; } } a[1].value = id; a[1].value_len = id_size; } else { a[1].value = cid->data; a[1].value_len = cid->size; } a[2].type = CKA_VALUE; a[2].value = der; a[2].value_len = der_size; a[3].type = CKA_TOKEN; a[3].value = (void *) &tval; a[3].value_len = sizeof(tval); a[4].type = CKA_CERTIFICATE_TYPE; a[4].value = &type; a[4].value_len = sizeof(type); /* FIXME: copy key usage flags */ a_val = 5; a[a_val].type = CKA_SUBJECT; a[a_val].value = crt->raw_dn.data; a[a_val].value_len = crt->raw_dn.size; a_val++; a[a_val].type = CKA_ISSUER; a[a_val].value = crt->raw_issuer_dn.data; a[a_val].value_len = crt->raw_issuer_dn.size; a_val++; serial_size = sizeof(serial); if (gnutls_x509_crt_get_serial(crt, serial, &serial_size) >= 0) { ret = _gnutls_x509_ext_gen_number(serial, serial_size, &serial_der); if (ret >= 0) { a[a_val].type = CKA_SERIAL_NUMBER; a[a_val].value = (void *) serial_der.data; a[a_val].value_len = serial_der.size; a_val++; } } if (label) { a[a_val].type = CKA_LABEL; a[a_val].value = (void *) label; a[a_val].value_len = strlen(label); a_val++; } mark_flags(flags, a, &a_val, sinfo.trusted); rv = pkcs11_create_object(sinfo.module, sinfo.pks, a, a_val, &ctx); if (rv != CKR_OK) { gnutls_assert(); _gnutls_debug_log("p11: %s\n", pkcs11_strerror(rv)); ret = pkcs11_rv_to_err(rv); goto cleanup; } /* generated! */ ret = 0; cleanup: gnutls_free(der); gnutls_free(serial_der.data); pkcs11_close_session(&sinfo); return ret; }
/* auto-generate a set of self signed certificates */ void tls_cert_generate(TALLOC_CTX *mem_ctx, const char *hostname, const char *keyfile, const char *certfile, const char *cafile) { gnutls_x509_crt cacrt, crt; gnutls_x509_privkey key, cakey; uint32_t serial = (uint32_t)time(NULL); unsigned char keyid[100]; char buf[4096]; size_t bufsize; size_t keyidsize = sizeof(keyid); time_t activation = time(NULL), expiry = activation + LIFETIME; int ret; if (file_exist(keyfile) || file_exist(certfile) || file_exist(cafile)) { DEBUG(0,("TLS autogeneration skipped - some TLS files already exist\n")); return; } #define TLSCHECK(call) do { \ ret = call; \ if (ret < 0) { \ DEBUG(0,("TLS %s - %s\n", #call, gnutls_strerror(ret))); \ goto failed; \ } \ } while (0) TLSCHECK(gnutls_global_init()); DEBUG(0,("Attempting to autogenerate TLS self-signed keys for https for hostname '%s'\n", hostname)); #if defined(HAVE_GCRYPT_H) && !defined(HAVE_GNUTLS3) DEBUG(3,("Enabling QUICK mode in gcrypt\n")); gcry_control(GCRYCTL_ENABLE_QUICK_RANDOM, 0); #endif DEBUG(3,("Generating private key\n")); TLSCHECK(gnutls_x509_privkey_init(&key)); TLSCHECK(gnutls_x509_privkey_generate(key, GNUTLS_PK_RSA, RSA_BITS, 0)); DEBUG(3,("Generating CA private key\n")); TLSCHECK(gnutls_x509_privkey_init(&cakey)); TLSCHECK(gnutls_x509_privkey_generate(cakey, GNUTLS_PK_RSA, RSA_BITS, 0)); DEBUG(3,("Generating CA certificate\n")); TLSCHECK(gnutls_x509_crt_init(&cacrt)); TLSCHECK(gnutls_x509_crt_set_dn_by_oid(cacrt, GNUTLS_OID_X520_ORGANIZATION_NAME, 0, ORGANISATION_NAME, strlen(ORGANISATION_NAME))); TLSCHECK(gnutls_x509_crt_set_dn_by_oid(cacrt, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, 0, CA_NAME, strlen(CA_NAME))); TLSCHECK(gnutls_x509_crt_set_dn_by_oid(cacrt, GNUTLS_OID_X520_COMMON_NAME, 0, hostname, strlen(hostname))); TLSCHECK(gnutls_x509_crt_set_key(cacrt, cakey)); TLSCHECK(gnutls_x509_crt_set_serial(cacrt, &serial, sizeof(serial))); TLSCHECK(gnutls_x509_crt_set_activation_time(cacrt, activation)); TLSCHECK(gnutls_x509_crt_set_expiration_time(cacrt, expiry)); TLSCHECK(gnutls_x509_crt_set_ca_status(cacrt, 1)); TLSCHECK(gnutls_x509_crt_set_key_usage(cacrt, GNUTLS_KEY_KEY_CERT_SIGN | GNUTLS_KEY_CRL_SIGN)); TLSCHECK(gnutls_x509_crt_set_version(cacrt, 3)); TLSCHECK(gnutls_x509_crt_get_key_id(cacrt, 0, keyid, &keyidsize)); #if HAVE_GNUTLS_X509_CRT_SET_SUBJECT_KEY_ID TLSCHECK(gnutls_x509_crt_set_subject_key_id(cacrt, keyid, keyidsize)); #endif TLSCHECK(gnutls_x509_crt_sign2(cacrt, cacrt, cakey, GNUTLS_DIG_SHA256, 0)); DEBUG(3,("Generating TLS certificate\n")); TLSCHECK(gnutls_x509_crt_init(&crt)); TLSCHECK(gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_ORGANIZATION_NAME, 0, ORGANISATION_NAME, strlen(ORGANISATION_NAME))); TLSCHECK(gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, 0, UNIT_NAME, strlen(UNIT_NAME))); TLSCHECK(gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COMMON_NAME, 0, hostname, strlen(hostname))); TLSCHECK(gnutls_x509_crt_set_key(crt, key)); TLSCHECK(gnutls_x509_crt_set_serial(crt, &serial, sizeof(serial))); TLSCHECK(gnutls_x509_crt_set_activation_time(crt, activation)); TLSCHECK(gnutls_x509_crt_set_expiration_time(crt, expiry)); TLSCHECK(gnutls_x509_crt_set_ca_status(crt, 0)); #ifdef GNUTLS_KP_TLS_WWW_SERVER TLSCHECK(gnutls_x509_crt_set_key_purpose_oid(crt, GNUTLS_KP_TLS_WWW_SERVER, 0)); #endif TLSCHECK(gnutls_x509_crt_set_version(crt, 3)); TLSCHECK(gnutls_x509_crt_get_key_id(crt, 0, keyid, &keyidsize)); #if HAVE_GNUTLS_X509_CRT_SET_SUBJECT_KEY_ID TLSCHECK(gnutls_x509_crt_set_subject_key_id(crt, keyid, keyidsize)); #endif TLSCHECK(gnutls_x509_crt_sign2(crt, crt, key, GNUTLS_DIG_SHA256, 0)); TLSCHECK(gnutls_x509_crt_sign2(crt, cacrt, cakey, GNUTLS_DIG_SHA256, 0)); DEBUG(3,("Exporting TLS keys\n")); bufsize = sizeof(buf); TLSCHECK(gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_PEM, buf, &bufsize)); if (!file_save(certfile, buf, bufsize)) { DEBUG(0,("Unable to save certificate in %s parent dir exists ?\n", certfile)); goto failed; } bufsize = sizeof(buf); TLSCHECK(gnutls_x509_crt_export(cacrt, GNUTLS_X509_FMT_PEM, buf, &bufsize)); if (!file_save(cafile, buf, bufsize)) { DEBUG(0,("Unable to save ca cert in %s parent dir exists ?\n", cafile)); goto failed; } bufsize = sizeof(buf); TLSCHECK(gnutls_x509_privkey_export(key, GNUTLS_X509_FMT_PEM, buf, &bufsize)); if (!file_save_mode(keyfile, buf, bufsize, 0600)) { DEBUG(0,("Unable to save privatekey in %s parent dir exists ?\n", keyfile)); goto failed; } gnutls_x509_privkey_deinit(key); gnutls_x509_privkey_deinit(cakey); gnutls_x509_crt_deinit(cacrt); gnutls_x509_crt_deinit(crt); gnutls_global_deinit(); DEBUG(0,("TLS self-signed keys generated OK\n")); return; failed: DEBUG(0,("TLS certificate generation failed\n")); }
bool load_p12(gnutls_certificate_credentials_t xcred, const char *const p12_file, const char *const password) { FILE*p12file; gnutls_datum_t p12blob; gnutls_pkcs12_t p12 = NULL; gnutls_x509_privkey_t key = NULL; gnutls_x509_crt_t certs[MAX_CERTS]; int certs_nr; int id_cert; uint8_t key_id[20]; size_t key_id_size; bool is_success = false; int ret; int i; assert(p12_file != NULL); /* Read file */ p12file = fopen(p12_file, "rb"); if(p12file == NULL) { trace(LOG_ERR, "failed to open PKCS#12 file '%s': %s (%d)", p12_file, strerror(errno), errno); ret = GNUTLS_E_FILE_ERROR; goto error; } p12blob.data = malloc(32768 * sizeof(char)); p12blob.size = fread((void*) p12blob.data, sizeof(char), 32768, p12file); fclose(p12file); /* Init structure and import P12 */ ret = gnutls_pkcs12_init(&p12); if(ret < 0) { trace(LOG_ERR, "failed to init PKCS#12 object (%d)", ret); goto free_blob; } ret = gnutls_pkcs12_import(p12, &p12blob, GNUTLS_X509_FMT_DER, 0); if(ret < 0) { trace(LOG_ERR, "failed to import PKCS#12 data (%d)", ret); goto deinit_pkcs12; } if(password) { ret = gnutls_pkcs12_verify_mac(p12, password); if(ret < 0) { trace(LOG_ERR, "failed to verify PKCS#12 MAC (%d)", ret); goto deinit_pkcs12; } } /* extract the private key and the certificates from PKCS#12 */ if(!tls_parse_pkcs12(&p12, password, &key, certs, &certs_nr)) { trace(LOG_ERR, "failed to parse PKCS#12 file '%s'", p12_file); goto deinit_pkcs12; } if(certs_nr < 2) { trace(LOG_ERR, "too few certificates in PKCS#12 file '%s'", p12_file); goto free_certs_key; } /* get the ID of private key */ key_id_size = sizeof(key_id); ret = gnutls_x509_privkey_get_key_id(key, 0, key_id, &key_id_size); if(ret < 0) { trace(LOG_ERR, "failed to get key ID"); goto free_certs_key; } id_cert = -1; for(i = 0; i < certs_nr; i++) { uint8_t cert_id[20]; size_t cert_id_size; cert_id_size = sizeof(cert_id); ret = gnutls_x509_crt_get_key_id(certs[i], 0, cert_id, &cert_id_size); if(ret < 0) { trace(LOG_ERR, "failed to get key ID for certificate #%d (%d)", i, ret); goto free_certs_key; } if(key_id_size == cert_id_size && memcmp(cert_id, key_id, cert_id_size) == 0) { /* it's the key certificate ! */ if(id_cert != -1) { ret = GNUTLS_E_INTERRUPTED; trace(LOG_ERR, "Duplicate key certificate !\n"); goto free_certs_key; } id_cert = i; } } if(id_cert == -1) { ret = GNUTLS_E_INTERRUPTED; trace(LOG_ERR, "Unable to find key certificate !\n"); goto free_certs_key; } /* Now have fun with the key and certs ! */ ret = gnutls_certificate_set_x509_key(xcred, &certs[id_cert], 1, key); if(ret < 0) { trace(LOG_ERR, "failed to set key for main certificate"); goto free_certs_key; } for(i = 0; i < certs_nr; i++) { if(i != id_cert) { ret = gnutls_certificate_set_x509_trust(xcred, &certs[i], 1); if(ret < 0) { trace(LOG_ERR, "failed to trust certificate #%d", i + 1); goto free_certs_key; } } } is_success = true; free_certs_key: gnutls_x509_privkey_deinit(key); for(i = 0; i < certs_nr; i++) { gnutls_x509_crt_deinit(certs[i]); } deinit_pkcs12: gnutls_pkcs12_deinit(p12); free_blob: free(p12blob.data); error: return is_success; }
/** * gnutls_system_key_add_x509: * @crt: the certificate to be added * @privkey: the key to be added * @label: the friendly name to describe the key * @cert_url: if non-NULL it will contain an allocated value with the certificate URL * @key_url: if non-NULL it will contain an allocated value with the key URL * * This function will added the given key and certificate pair, * to the system list. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 3.4.0 **/ int gnutls_system_key_add_x509(gnutls_x509_crt_t crt, gnutls_x509_privkey_t privkey, const char *label, char **cert_url, char **key_url) { HCERTSTORE store = NULL; CRYPT_DATA_BLOB pfx; gnutls_datum_t _pfx = { NULL, 0 }; gnutls_pkcs12_t p12 = NULL; gnutls_pkcs12_bag_t bag1 = NULL, bag2 = NULL; uint8_t id[MAX_WID_SIZE]; size_t id_size; gnutls_datum_t kid; int ret; if (ncrypt_init == 0) return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE); if (label == NULL) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); id_size = sizeof(id); ret = gnutls_x509_crt_get_key_id(crt, 0, id, &id_size); if (ret < 0) return gnutls_assert_val(ret); kid.data = id; kid.size = id_size; /* the idea: import the cert and private key into PKCS #12 * format, export it into pfx, and import it into store */ ret = gnutls_pkcs12_init(&p12); if (ret < 0) return gnutls_assert_val(ret); ret = gnutls_pkcs12_bag_init(&bag1); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = gnutls_pkcs12_bag_set_crt(bag1, crt); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = gnutls_pkcs12_bag_set_key_id(bag1, 0, &kid); if (ret < 0) { gnutls_assert(); goto cleanup; } if (label) gnutls_pkcs12_bag_set_friendly_name(bag1, 0, label); ret = gnutls_pkcs12_bag_init(&bag2); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = gnutls_pkcs12_bag_set_privkey(bag2, privkey, NULL, 0); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = gnutls_pkcs12_bag_set_key_id(bag2, 0, &kid); if (ret < 0) { gnutls_assert(); goto cleanup; } if (label) gnutls_pkcs12_bag_set_friendly_name(bag2, 0, label); ret = gnutls_pkcs12_set_bag(p12, bag1); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = gnutls_pkcs12_set_bag(p12, bag2); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = gnutls_pkcs12_generate_mac(p12, "123456"); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = gnutls_pkcs12_export2(p12, GNUTLS_X509_FMT_DER, &_pfx); if (ret < 0) { gnutls_assert(); goto cleanup; } pfx.cbData = _pfx.size; pfx.pbData = _pfx.data; store = PFXImportCertStore(&pfx, L"123456", 0); if (store == NULL) { gnutls_assert(); ret = GNUTLS_E_INVALID_REQUEST; goto cleanup; } if (cert_url || key_url) { unsigned char sha[20]; CRYPT_HASH_BLOB blob; const CERT_CONTEXT *cert = NULL; gnutls_datum_t data; ret = gnutls_x509_crt_export2(crt, GNUTLS_X509_FMT_DER, &data); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = gnutls_hash_fast(GNUTLS_DIG_SHA1, data.data, data.size, sha); gnutls_free(data.data); if (ret < 0) { gnutls_assert(); goto cleanup; } blob.cbData = sizeof(sha); blob.pbData = sha; cert = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0, CERT_FIND_SHA1_HASH, &blob, NULL); if (cert == NULL) { gnutls_assert(); ret = GNUTLS_E_KEY_IMPORT_FAILED; goto cleanup; } ret = get_win_urls(cert, cert_url, key_url, NULL, NULL); if (ret < 0) { gnutls_assert(); goto cleanup; } } ret = 0; cleanup: if (p12 != NULL) gnutls_pkcs12_deinit(p12); if (bag1 != NULL) gnutls_pkcs12_bag_deinit(bag1); if (bag2 != NULL) gnutls_pkcs12_bag_deinit(bag2); if (store != NULL) CertCloseStore(store, 0); gnutls_free(_pfx.data); return ret; }
/** * gnutls_pkcs11_copy_x509_crt: * @token_url: A PKCS #11 URL specifying a token * @crt: A certificate * @label: A name to be used for the stored data * @flags: One of GNUTLS_PKCS11_OBJ_FLAG_* * * This function will copy a certificate into a PKCS #11 token specified by * a URL. The certificate can be marked as trusted or not. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 2.12.0 **/ int gnutls_pkcs11_copy_x509_crt(const char *token_url, gnutls_x509_crt_t crt, const char *label, unsigned int flags) { int ret; struct p11_kit_uri *info = NULL; ck_rv_t rv; size_t der_size, id_size; uint8_t *der = NULL; uint8_t id[20]; struct ck_attribute a[16]; ck_object_class_t class = CKO_CERTIFICATE; ck_certificate_type_t type = CKC_X_509; ck_object_handle_t obj; int a_val; unsigned long category; struct pkcs11_session_info sinfo; PKCS11_CHECK_INIT; memset(&sinfo, 0, sizeof(sinfo)); ret = pkcs11_url_to_info(token_url, &info); if (ret < 0) { gnutls_assert(); return ret; } ret = pkcs11_open_session(&sinfo, NULL, info, SESSION_WRITE | pkcs11_obj_flags_to_int(flags)); p11_kit_uri_free(info); if (ret < 0) { gnutls_assert(); return ret; } der_size = 0; ret = gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_DER, NULL, &der_size); if (ret < 0 && ret != GNUTLS_E_SHORT_MEMORY_BUFFER) { gnutls_assert(); goto cleanup; } der = gnutls_malloc(der_size); if (der == NULL) { gnutls_assert(); ret = GNUTLS_E_MEMORY_ERROR; goto cleanup; } ret = gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_DER, der, &der_size); if (ret < 0) { gnutls_assert(); goto cleanup; } id_size = sizeof(id); ret = gnutls_x509_crt_get_subject_key_id(crt, id, &id_size, NULL); if (ret < 0) { id_size = sizeof(id); ret = gnutls_x509_crt_get_key_id(crt, 0, id, &id_size); if (ret < 0) { gnutls_assert(); goto cleanup; } } /* FIXME: copy key usage flags */ a[0].type = CKA_CLASS; a[0].value = &class; a[0].value_len = sizeof(class); a[1].type = CKA_ID; a[1].value = id; a[1].value_len = id_size; a[2].type = CKA_VALUE; a[2].value = der; a[2].value_len = der_size; a[3].type = CKA_TOKEN; a[3].value = (void *) &tval; a[3].value_len = sizeof(tval); a[4].type = CKA_CERTIFICATE_TYPE; a[4].value = &type; a[4].value_len = sizeof(type); a_val = 5; a[a_val].type = CKA_SUBJECT; a[a_val].value = crt->raw_dn.data; a[a_val].value_len = crt->raw_dn.size; a_val++; if (label) { a[a_val].type = CKA_LABEL; a[a_val].value = (void *) label; a[a_val].value_len = strlen(label); a_val++; } if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_CA) { category = 2; a[a_val].type = CKA_CERTIFICATE_CATEGORY; a[a_val].value = (void *) &category; a[a_val].value_len = sizeof(category); a_val++; } if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_TRUSTED) { a[a_val].type = CKA_TRUSTED; a[a_val].value = (void *) &tval; a[a_val].value_len = sizeof(tval); a_val++; a[a_val].type = CKA_PRIVATE; a[a_val].value = (void *) &fval; a[a_val].value_len = sizeof(fval); a_val++; } else { if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_PRIVATE) { a[a_val].type = CKA_PRIVATE; a[a_val].value = (void *) &tval; a[a_val].value_len = sizeof(tval); a_val++; } else if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_NOT_PRIVATE) { a[a_val].type = CKA_PRIVATE; a[a_val].value = (void *) &fval; a[a_val].value_len = sizeof(fval); a_val++; } } rv = pkcs11_create_object(sinfo.module, sinfo.pks, a, a_val, &obj); if (rv != CKR_OK) { gnutls_assert(); _gnutls_debug_log("p11: %s\n", pkcs11_strerror(rv)); ret = pkcs11_rv_to_err(rv); goto cleanup; } /* generated! */ ret = 0; cleanup: gnutls_free(der); pkcs11_close_session(&sinfo); return ret; }
void Plugin::_loadCertificate() { QFile file(this->crtFile); gnutls_datum_t datum; size_t size = 2048; QByteArray data; gnutls_privkey_t privkey; gnutls_pubkey_t pubkey; gnutls_pubkey_t pubkeyCrt; int error; QMap<char *, QByteArray> oid; gnutls_digest_algorithm_t digest; if (!file.open(QIODevice::ReadWrite)) throw Properties("error", "Unable to open the certificate file").add("file", this->crtFile); ASSERT_INIT(gnutls_x509_crt_init(&this->crt), "crt"); ASSERT(gnutls_privkey_init(&privkey)); ASSERT(gnutls_privkey_import_x509(privkey, this->key, 0)); ASSERT(gnutls_pubkey_init(&pubkey)); ASSERT(gnutls_pubkey_import_privkey(pubkey, privkey, 0, 0)); // Verifies that the certificate is valid if (file.size() > 0) { ASSERT(gnutls_pubkey_init(&pubkeyCrt)); data = file.readAll(); datum.size = data.size(); datum.data = (unsigned char *)data.data(); if (gnutls_x509_crt_import(this->crt, &datum, GNUTLS_X509_FMT_PEM) != GNUTLS_E_SUCCESS) file.resize(0); else if (gnutls_x509_crt_get_expiration_time(this->crt) < ::time(NULL) + CRT_EXPIRATION_REGEN) file.resize(0); else if (gnutls_pubkey_import_x509(pubkeyCrt, this->crt, 0) != GNUTLS_E_SUCCESS) file.resize(0); // Ensures that the public keys of the certificate and the private key match size_t size1 = size, size2 = size; QByteArray pub1((int)size1, 0), pub2((int)size2, 0); if (gnutls_pubkey_export(pubkey, GNUTLS_X509_FMT_PEM, pub1.data(), &size1) != GNUTLS_E_SUCCESS || gnutls_pubkey_export(pubkeyCrt, GNUTLS_X509_FMT_PEM, pub2.data(), &size2) != GNUTLS_E_SUCCESS || size1 != size2 || pub1 != pub2) file.resize(0); gnutls_pubkey_deinit(pubkeyCrt); } // Generates a new certificate if (file.size() == 0) { gnutls_x509_crt_deinit(this->crt); this->init.removeAll("crt"); ASSERT_INIT(gnutls_x509_crt_init(&this->crt), "crt"); LOG_INFO("Generating a new certificate", "Plugin", "_generateCertificate"); oid.insert((char *)GNUTLS_OID_X520_COMMON_NAME, "LightBird"); oid.insert((char *)GNUTLS_OID_X520_ORGANIZATION_NAME, "LightBird"); QMapIterator<char *, QByteArray> it(oid); while (it.hasNext()) ASSERT(gnutls_x509_crt_set_dn_by_oid(this->crt, it.key(), 0, it.value().data(), it.next().value().size())); ASSERT(gnutls_x509_crt_set_pubkey(this->crt, pubkey)); data = this->_generateSerial(); ASSERT(gnutls_x509_crt_set_serial(this->crt, data.data(), data.size())); ASSERT(gnutls_x509_crt_set_activation_time(this->crt, ::time(NULL))); ASSERT(gnutls_x509_crt_set_expiration_time(this->crt, ::time(NULL) + CRT_EXPIRATION)); ASSERT(gnutls_x509_crt_set_basic_constraints(this->crt, 0, -1)); ASSERT(gnutls_x509_crt_set_key_purpose_oid(this->crt, GNUTLS_KP_TLS_WWW_SERVER, 0)); ASSERT(gnutls_x509_crt_set_key_usage(this->crt, GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT)); data.resize((int)size); ASSERT(gnutls_x509_crt_get_key_id(this->crt, 0, (unsigned char *)data.data(), &size)); ASSERT(gnutls_x509_crt_set_subject_key_id(this->crt, (unsigned char *)data.data(), size)); ASSERT(gnutls_x509_crt_set_version(this->crt, 3)); ASSERT(gnutls_pubkey_get_preferred_hash_algorithm(pubkey, &digest, NULL)); ASSERT(gnutls_x509_crt_privkey_sign(this->crt, this->crt, privkey, digest, 0)); size = data.size(); ASSERT(gnutls_x509_crt_export(this->crt, GNUTLS_X509_FMT_PEM, data.data(), &size)); data.resize((int)size); file.write(data); } gnutls_pubkey_deinit(pubkey); gnutls_privkey_deinit(privkey); }
int /* O - 1 on success, 0 on failure */ cupsMakeServerCredentials( const char *path, /* I - Path to keychain/directory */ const char *common_name, /* I - Common name */ int num_alt_names, /* I - Number of subject alternate names */ const char **alt_names, /* I - Subject Alternate Names */ time_t expiration_date) /* I - Expiration date */ { gnutls_x509_crt_t crt; /* Self-signed certificate */ gnutls_x509_privkey_t key; /* Encryption private key */ char temp[1024], /* Temporary directory name */ crtfile[1024], /* Certificate filename */ keyfile[1024]; /* Private key filename */ 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 */ DEBUG_printf(("cupsMakeServerCredentials(path=\"%s\", common_name=\"%s\", num_alt_names=%d, alt_names=%p, expiration_date=%d)", path, common_name, num_alt_names, alt_names, (int)expiration_date)); /* * Filenames... */ if (!path) path = http_gnutls_default_path(temp, sizeof(temp)); if (!path || !common_name) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); return (0); } http_gnutls_make_path(crtfile, sizeof(crtfile), path, common_name, "crt"); http_gnutls_make_path(keyfile, sizeof(keyfile), path, common_name, "key"); /* * Create the encryption key... */ DEBUG_puts("1cupsMakeServerCredentials: Creating key pair."); gnutls_x509_privkey_init(&key); gnutls_x509_privkey_generate(key, GNUTLS_PK_RSA, 2048, 0); DEBUG_puts("1cupsMakeServerCredentials: Key pair created."); /* * Save it... */ bytes = sizeof(buffer); if ((result = gnutls_x509_privkey_export(key, GNUTLS_X509_FMT_PEM, buffer, &bytes)) < 0) { DEBUG_printf(("1cupsMakeServerCredentials: Unable to export private key: %s", gnutls_strerror(result))); _cupsSetError(IPP_STATUS_ERROR_INTERNAL, gnutls_strerror(result), 0); gnutls_x509_privkey_deinit(key); return (0); } else if ((fp = cupsFileOpen(keyfile, "w")) != NULL) { DEBUG_printf(("1cupsMakeServerCredentials: Writing private key to \"%s\".", keyfile)); cupsFileWrite(fp, (char *)buffer, bytes); cupsFileClose(fp); } else { DEBUG_printf(("1cupsMakeServerCredentials: Unable to create private key file \"%s\": %s", keyfile, strerror(errno))); _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); gnutls_x509_privkey_deinit(key); return (0); } /* * Create the self-signed certificate... */ DEBUG_puts("1cupsMakeServerCredentials: Generating self-signed X.509 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, common_name, strlen(common_name)); gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_ORGANIZATION_NAME, 0, common_name, strlen(common_name)); 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); if (num_alt_names > 0) gnutls_x509_crt_set_subject_alternative_name(crt, GNUTLS_SAN_DNSNAME, alt_names[0]); 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) { DEBUG_printf(("1cupsMakeServerCredentials: Unable to export public key and X.509 certificate: %s", gnutls_strerror(result))); _cupsSetError(IPP_STATUS_ERROR_INTERNAL, gnutls_strerror(result), 0); gnutls_x509_crt_deinit(crt); gnutls_x509_privkey_deinit(key); return (0); } else if ((fp = cupsFileOpen(crtfile, "w")) != NULL) { DEBUG_printf(("1cupsMakeServerCredentials: Writing public key and X.509 certificate to \"%s\".", crtfile)); cupsFileWrite(fp, (char *)buffer, bytes); cupsFileClose(fp); } else { DEBUG_printf(("1cupsMakeServerCredentials: Unable to create public key and X.509 certificate file \"%s\": %s", crtfile, strerror(errno))); _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); gnutls_x509_crt_deinit(crt); gnutls_x509_privkey_deinit(key); return (0); } /* * Cleanup... */ gnutls_x509_crt_deinit(crt); gnutls_x509_privkey_deinit(key); DEBUG_puts("1cupsMakeServerCredentials: Successfully created credentials."); return (1); }
/** * gnutls_pkcs12_simple_parse: * @p12: A pkcs12 type * @password: optional password used to decrypt the structure, bags and keys. * @key: a structure to store the parsed private key. * @chain: the corresponding to key certificate chain (may be %NULL) * @chain_len: will be updated with the number of additional (may be %NULL) * @extra_certs: optional pointer to receive an array of additional * certificates found in the PKCS12 structure (may be %NULL). * @extra_certs_len: will be updated with the number of additional * certs (may be %NULL). * @crl: an optional structure to store the parsed CRL (may be %NULL). * @flags: should be zero or one of GNUTLS_PKCS12_SP_* * * This function parses a PKCS12 structure in @pkcs12 and extracts the * private key, the corresponding certificate chain, any additional * certificates and a CRL. The structures in @key, @chain @crl, and @extra_certs * must not be initialized. * * The @extra_certs and @extra_certs_len parameters are optional * and both may be set to %NULL. If either is non-%NULL, then both must * be set. The value for @extra_certs is allocated * using gnutls_malloc(). * * Encrypted PKCS12 bags and PKCS8 private keys are supported, but * only with password based security and the same password for all * operations. * * Note that a PKCS12 structure may contain many keys and/or certificates, * and there is no way to identify which key/certificate pair you want. * For this reason this function is useful for PKCS12 files that contain * only one key/certificate pair and/or one CRL. * * If the provided structure has encrypted fields but no password * is provided then this function returns %GNUTLS_E_DECRYPTION_FAILED. * * Note that normally the chain constructed does not include self signed * certificates, to comply with TLS' requirements. If, however, the flag * %GNUTLS_PKCS12_SP_INCLUDE_SELF_SIGNED is specified then * self signed certificates will be included in the chain. * * Prior to using this function the PKCS #12 structure integrity must * be verified using gnutls_pkcs12_verify_mac(). * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 3.1.0 **/ 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; uint8_t cert_id[20]; uint8_t key_id[20]; int privkey_ok = 0; unsigned int i; int elements_in_bag; *key = NULL; if (crl) *crl = NULL; /* find the first private key */ for (;;) { 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) { gnutls_pkcs12_bag_deinit(bag); bag = NULL; 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 < (unsigned)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; } FALLTHROUGH; 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(); 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(); goto done; } privkey_ok = 1; /* break */ break; default: break; } } idx++; gnutls_pkcs12_bag_deinit(bag); bag = NULL; 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 (;;) { 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) { gnutls_pkcs12_bag_deinit(bag); bag = NULL; 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 < (unsigned)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); this_cert = NULL; 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); this_cert = NULL; goto done; } if (memcmp(cert_id, key_id, cert_id_size) != 0) { /* they don't match - skip the certificate */ _extra_certs = gnutls_realloc_fast (_extra_certs, sizeof(_extra_certs [0]) * ++_extra_certs_len); if (!_extra_certs) { gnutls_assert(); ret = GNUTLS_E_MEMORY_ERROR; goto done; } _extra_certs [_extra_certs_len - 1] = this_cert; this_cert = NULL; } else { if (chain && _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); this_cert = NULL; } } 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); *crl = NULL; 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); bag = NULL; } if (chain != NULL) { if (_chain_len != 1) { ret = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; goto done; } ret = make_chain(&_chain, &_chain_len, &_extra_certs, &_extra_certs_len, flags); 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); *key = NULL; } if (crl != NULL && *crl != NULL) { gnutls_x509_crl_deinit(*crl); *crl = NULL; } if (_extra_certs_len && _extra_certs != NULL) { for (i = 0; i < _extra_certs_len; i++) gnutls_x509_crt_deinit(_extra_certs[i]); gnutls_free(_extra_certs); } if (_chain_len && _chain != NULL) { for (i = 0; i < _chain_len; i++) gnutls_x509_crt_deinit(_chain[i]); gnutls_free(_chain); } return ret; } if (extra_certs && _extra_certs_len > 0) { *extra_certs = _extra_certs; *extra_certs_len = _extra_certs_len; } else { if (extra_certs) { *extra_certs = NULL; *extra_certs_len = 0; } for (i = 0; i < _extra_certs_len; i++) gnutls_x509_crt_deinit(_extra_certs[i]); gnutls_free(_extra_certs); } if (chain != NULL) { *chain = _chain; *chain_len = _chain_len; } return ret; }
void doit(void) { gnutls_pkcs12_t pkcs12; gnutls_x509_crt_t client; gnutls_x509_crt_t ca; gnutls_pkcs12_bag_t bag; unsigned char key_id_buf[20]; gnutls_datum_t key_id; int ret, indx; char outbuf[10240]; size_t size; unsigned tests, i; ret = global_init(); if (ret < 0) { fprintf(stderr, "global_init %d", ret); exit(1); } gnutls_global_set_log_function(tls_log_func); if (debug) gnutls_global_set_log_level(4711); /* Read certs. */ ret = gnutls_x509_crt_init(&client); if (ret < 0) { fprintf(stderr, "crt_init: %d", ret); exit(1); } ret = gnutls_x509_crt_import(client, &client_dat, GNUTLS_X509_FMT_PEM); if (ret < 0) { fprintf(stderr, "crt_import: %d", ret); exit(1); } ret = gnutls_x509_crt_init(&ca); if (ret < 0) { fprintf(stderr, "ca_init: %d", ret); exit(1); } ret = gnutls_x509_crt_import(ca, &ca_dat, GNUTLS_X509_FMT_PEM); if (ret < 0) { fprintf(stderr, "ca_import: %d", ret); exit(1); } /* Create PKCS#12 structure. */ ret = gnutls_pkcs12_init(&pkcs12); if (ret < 0) { fprintf(stderr, "pkcs12_init: %d", ret); exit(1); } /* Generate and add PKCS#12 cert bags. */ #ifndef ENABLE_FIPS140 tests = 2; /* include RC2 */ #else tests = 1; #endif for (i = 0; i < tests; i++) { ret = gnutls_pkcs12_bag_init(&bag); if (ret < 0) { fprintf(stderr, "bag_init: %s (%d)\n", gnutls_strerror(ret), ret); exit(1); } ret = gnutls_pkcs12_bag_set_crt(bag, i == 0 ? client : ca); if (ret < 0) { fprintf(stderr, "set_crt: %s (%d)\n", gnutls_strerror(ret), ret); exit(1); } indx = ret; ret = gnutls_pkcs12_bag_set_friendly_name(bag, indx, i == 0 ? "client" : "ca"); if (ret < 0) { fprintf(stderr, "set_friendly_name: %s (%d)\n", gnutls_strerror(ret), ret); exit(1); } size = sizeof(key_id_buf); ret = gnutls_x509_crt_get_key_id(i == 0 ? client : ca, 0, key_id_buf, &size); if (ret < 0) { fprintf(stderr, "get_key_id: %s (%d)\n", gnutls_strerror(ret), ret); exit(1); } key_id.data = key_id_buf; key_id.size = size; ret = gnutls_pkcs12_bag_set_key_id(bag, indx, &key_id); if (ret < 0) { fprintf(stderr, "bag_set_key_id: %s (%d)\n", gnutls_strerror(ret), ret); exit(1); } ret = gnutls_pkcs12_bag_encrypt(bag, "pass", i == 0 ? GNUTLS_PKCS8_USE_PKCS12_3DES : GNUTLS_PKCS_USE_PKCS12_RC2_40); if (ret < 0) { fprintf(stderr, "bag_encrypt: %d: %s", ret, i == 0 ? "3DES" : "RC2-40"); exit(1); } ret = gnutls_pkcs12_set_bag(pkcs12, bag); if (ret < 0) { fprintf(stderr, "set_bag: %s (%d)\n", gnutls_strerror(ret), ret); exit(1); } gnutls_pkcs12_bag_deinit(bag); } /* MAC the structure, export and print. */ ret = gnutls_pkcs12_generate_mac2(pkcs12, GNUTLS_MAC_SHA1, "pass"); if (ret < 0) { fprintf(stderr, "generate_mac: %s (%d)\n", gnutls_strerror(ret), ret); exit(1); } ret = gnutls_pkcs12_verify_mac(pkcs12, "pass"); if (ret < 0) { fprintf(stderr, "verify_mac: %s (%d)\n", gnutls_strerror(ret), ret); exit(1); } ret = gnutls_pkcs12_generate_mac2(pkcs12, GNUTLS_MAC_SHA256, "passwd"); if (ret < 0) { fprintf(stderr, "generate_mac2: %s (%d)\n", gnutls_strerror(ret), ret); exit(1); } ret = gnutls_pkcs12_verify_mac(pkcs12, "passwd"); if (ret < 0) { fprintf(stderr, "verify_mac2: %s (%d)\n", gnutls_strerror(ret), ret); exit(1); } size = sizeof(outbuf); ret = gnutls_pkcs12_export(pkcs12, GNUTLS_X509_FMT_PEM, outbuf, &size); if (ret < 0) { fprintf(stderr, "pkcs12_export: %s (%d)\n", gnutls_strerror(ret), ret); exit(1); } if (debug) fwrite(outbuf, size, 1, stdout); /* Cleanup. */ gnutls_pkcs12_deinit(pkcs12); gnutls_x509_crt_deinit(client); gnutls_x509_crt_deinit(ca); gnutls_global_deinit(); }
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); }