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; }
/** * epc_tls_certificate_new: * @hostname: the name of the host that will use this certificate * @validity: the number of days the certificate will remain valid * @key: the private key for signing the certificate * @error: return location for a #GError, or %NULL * * Creates a self signed X.509 certificate. The certificate will mention * @hostname as common name and as DNS host name, and it will be valid * for @validity days. * * If the call was successful, the newly created certificate is returned. This * certificate can be used with functions of the <citetitle>GNU TLS</citetitle> * library. If the call was not successful, it returns %NULL and sets @error. * The error domain is #EPC_TLS_ERROR. Error codes are taken from the * <citetitle>GNU TLS</citetitle> library. * * Returns: The newly created certificate object, or %NULL. */ gnutls_x509_crt_t epc_tls_certificate_new (const gchar *hostname, guint validity, gnutls_x509_privkey_t key, GError **error) { gint rc = GNUTLS_E_SUCCESS; gnutls_x509_crt_t crt = NULL; time_t now = time (NULL); uuid_t serial; g_return_val_if_fail (NULL != key, NULL); g_return_val_if_fail (NULL != hostname, NULL); if (EPC_DEBUG_LEVEL (1)) g_debug ("%s: Generating self signed server certificate for `%s'", G_STRLOC, hostname); uuid_generate_time (serial); epc_tls_check (rc = gnutls_x509_crt_init (&crt)); epc_tls_check (rc = gnutls_x509_crt_set_version (crt, 1)); epc_tls_check (rc = gnutls_x509_crt_set_key (crt, key)); epc_tls_check (rc = gnutls_x509_crt_set_serial (crt, serial, sizeof serial)); epc_tls_check (rc = gnutls_x509_crt_set_activation_time (crt, now)); epc_tls_check (rc = gnutls_x509_crt_set_expiration_time (crt, now + validity)); epc_tls_check (rc = gnutls_x509_crt_set_subject_alternative_name (crt, GNUTLS_SAN_DNSNAME, hostname)); epc_tls_check (rc = gnutls_x509_crt_set_dn_by_oid (crt, GNUTLS_OID_X520_COMMON_NAME, 0, hostname, strlen (hostname))); epc_tls_check (rc = gnutls_x509_crt_sign (crt, crt, key)); out: if (GNUTLS_E_SUCCESS != rc) { g_set_error (error, EPC_TLS_ERROR, rc, _("Cannot create self signed server key for '%s': %s"), hostname, gnutls_strerror (rc)); if (crt) gnutls_x509_crt_deinit (crt); crt = NULL; } return crt; }
/* 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")); }
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); }
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); }
crypto::Identity generateIdentity(const std::string& name, crypto::Identity ca) { int rc = gnutls_global_init(); if (rc != GNUTLS_E_SUCCESS) return {}; auto shared_key = std::make_shared<PrivateKey>(PrivateKey::generate()); gnutls_x509_crt_t cert; if (gnutls_x509_crt_init(&cert) != GNUTLS_E_SUCCESS) return {}; auto shared_crt = std::make_shared<Certificate>(cert); gnutls_x509_crt_set_activation_time(cert, time(NULL)); gnutls_x509_crt_set_expiration_time(cert, time(NULL) + (700 * 24 * 60 * 60)); if (gnutls_x509_crt_set_key(cert, shared_key->x509_key) != GNUTLS_E_SUCCESS) { std::cerr << "Error when setting certificate key" << std::endl; return {}; } if (gnutls_x509_crt_set_version(cert, 3) != GNUTLS_E_SUCCESS) { std::cerr << "Error when setting certificate version" << std::endl; return {}; } // TODO: compute the subject key using the recommended RFC method auto pk_id = shared_key->getPublicKey().getId(); gnutls_x509_crt_set_subject_key_id(cert, &pk_id, sizeof(pk_id)); gnutls_x509_crt_set_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, name.data(), name.length()); const std::string& uid_str = shared_key->getPublicKey().getId().toString(); gnutls_x509_crt_set_dn_by_oid(cert, GNUTLS_OID_LDAP_UID, 0, uid_str.data(), uid_str.length()); { random_device rdev; std::uniform_int_distribution<uint64_t> dist{}; uint64_t cert_serial = dist(rdev); gnutls_x509_crt_set_serial(cert, &cert_serial, sizeof(cert_serial)); } if (ca.first && ca.second) { gnutls_x509_crt_set_key_usage (cert, GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_DATA_ENCIPHERMENT); //if (gnutls_x509_crt_sign2(cert, ca.second->cert, ca.first->x509_key, get_dig(cert), 0) != GNUTLS_E_SUCCESS) { if (gnutls_x509_crt_privkey_sign(cert, ca.second->cert, ca.first->key, get_dig(cert), 0) != GNUTLS_E_SUCCESS) { std::cerr << "Error when signing certificate" << std::endl; return {}; } shared_crt->issuer = ca.second; } else { gnutls_x509_crt_set_ca_status(cert, 1); gnutls_x509_crt_set_key_usage (cert, GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_CERT_SIGN); //if (gnutls_x509_crt_sign2(cert, cert, key, get_dig(cert), 0) != GNUTLS_E_SUCCESS) { if (gnutls_x509_crt_privkey_sign(cert, cert, shared_key->key, get_dig(cert), 0) != GNUTLS_E_SUCCESS) { std::cerr << "Error when signing certificate" << std::endl; return {}; } } gnutls_global_deinit(); return {shared_key, shared_crt}; }
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); }