// Helper program based on the tor source code; makes a certificate // to use in testing our TLS implementation. // // This has to be done using OpenSSL's C API since there's no way to emulate // Tor's particular flavor of weirdness (version 3 certs with no extensions) // from the OpenSSL CLI. // // This is not meant to be used for anything but testing Arti. If you use // it for something else, you might regret it deeply. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include X509_NAME * tor_x509_name_new(const char *cname) { int nid; X509_NAME *name; if (!(name = X509_NAME_new())) return NULL; if ((nid = OBJ_txt2nid("commonName")) == NID_undef) goto error; if (!(X509_NAME_add_entry_by_NID(name, nid, MBSTRING_ASC, (unsigned char*)cname, -1, -1, 0))) goto error; return name; error: X509_NAME_free(name); return NULL; } X509 * tor_tls_create_certificate(EVP_PKEY *pkey, EVP_PKEY *sign_pkey, const char *cname, const char *cname_sign, unsigned int cert_lifetime) { /* OpenSSL generates self-signed certificates with random 64-bit serial * numbers, so let's do that too. */ #define SERIAL_NUMBER_SIZE 8 BIGNUM *serial_number = NULL; unsigned char serial_tmp[SERIAL_NUMBER_SIZE]; X509 *x509 = NULL; X509_NAME *name = NULL, *name_issuer=NULL; time_t start_time = time(NULL); time_t end_time = start_time + cert_lifetime; if (!(x509 = X509_new())) goto error; if (!(X509_set_version(x509, 2))) goto error; { /* our serial number is 8 random bytes. */ RAND_bytes(serial_tmp, sizeof(serial_tmp)); if (!(serial_number = BN_bin2bn(serial_tmp, sizeof(serial_tmp), NULL))) goto error; if (!(BN_to_ASN1_INTEGER(serial_number, X509_get_serialNumber(x509)))) goto error; } if (!(name = tor_x509_name_new(cname))) goto error; if (!(X509_set_subject_name(x509, name))) goto error; if (!(name_issuer = tor_x509_name_new(cname_sign))) goto error; if (!(X509_set_issuer_name(x509, name_issuer))) goto error; if (!X509_time_adj(X509_get_notBefore(x509),0,&start_time)) goto error; if (!X509_time_adj(X509_get_notAfter(x509),0,&end_time)) goto error; if (!X509_set_pubkey(x509, pkey)) goto error; if (!X509_sign(x509, sign_pkey, EVP_sha256())) goto error; goto done; error: fprintf(stderr, "Error making certificate\n"); if (x509) { X509_free(x509); x509 = NULL; } done: if (serial_number) BN_clear_free(serial_number); if (name) X509_NAME_free(name); if (name_issuer) X509_NAME_free(name_issuer); return x509; #undef SERIAL_NUMBER_SIZE } int main(int argc, char **argv) { OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL); EVP_PKEY *link = NULL, *sign = NULL; EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL); assert(ctx); if (EVP_PKEY_keygen_init(ctx) <= 0) { puts("BLAH"); return 1; } EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, 2048); int r1 = EVP_PKEY_keygen(ctx, &link); int r2 = EVP_PKEY_keygen(ctx, &sign); assert(r1 == 1 && r2 == 1); X509* x509 = tor_tls_create_certificate(link, sign, "Hello", "World", 86400); if (!x509) { return 1; } FILE *key = fopen("test.key", "w"); int r3 = PEM_write_PrivateKey(key, link, NULL, NULL, 0 , NULL, NULL); assert(r3 == 1); fclose(key); FILE *cert = fopen("test.crt", "w"); int r4 = PEM_write_X509(cert, x509); assert(r4 == 1); fclose(cert); puts("OK."); return 0; }