make-cert.c
1 // Helper program based on the tor source code; makes a certificate 2 // to use in testing our TLS implementation. 3 // 4 // This has to be done using OpenSSL's C API since there's no way to emulate 5 // Tor's particular flavor of weirdness (version 3 certs with no extensions) 6 // from the OpenSSL CLI. 7 // 8 // This is not meant to be used for anything but testing Arti. If you use 9 // it for something else, you might regret it deeply. 10 11 #include <stdio.h> 12 #include <stdlib.h> 13 #include <string.h> 14 #include <assert.h> 15 16 #include <openssl/opensslv.h> 17 #include <openssl/err.h> 18 #include <openssl/asn1.h> 19 #include <openssl/bio.h> 20 #include <openssl/bn.h> 21 #include <openssl/evp.h> 22 #include <openssl/objects.h> 23 #include <openssl/rand.h> 24 #include <openssl/rsa.h> 25 #include <openssl/ssl.h> 26 #include <openssl/x509.h> 27 28 X509_NAME * 29 tor_x509_name_new(const char *cname) 30 { 31 int nid; 32 X509_NAME *name; 33 if (!(name = X509_NAME_new())) 34 return NULL; 35 if ((nid = OBJ_txt2nid("commonName")) == NID_undef) goto error; 36 if (!(X509_NAME_add_entry_by_NID(name, nid, MBSTRING_ASC, 37 (unsigned char*)cname, -1, -1, 0))) 38 goto error; 39 return name; 40 41 error: 42 X509_NAME_free(name); 43 return NULL; 44 } 45 46 X509 * 47 tor_tls_create_certificate(EVP_PKEY *pkey, 48 EVP_PKEY *sign_pkey, 49 const char *cname, 50 const char *cname_sign, 51 unsigned int cert_lifetime) 52 { 53 /* OpenSSL generates self-signed certificates with random 64-bit serial 54 * numbers, so let's do that too. */ 55 #define SERIAL_NUMBER_SIZE 8 56 57 BIGNUM *serial_number = NULL; 58 unsigned char serial_tmp[SERIAL_NUMBER_SIZE]; 59 X509 *x509 = NULL; 60 X509_NAME *name = NULL, *name_issuer=NULL; 61 62 time_t start_time = time(NULL); 63 time_t end_time = start_time + cert_lifetime; 64 65 if (!(x509 = X509_new())) 66 goto error; 67 if (!(X509_set_version(x509, 2))) 68 goto error; 69 70 { /* our serial number is 8 random bytes. */ 71 RAND_bytes(serial_tmp, sizeof(serial_tmp)); 72 if (!(serial_number = BN_bin2bn(serial_tmp, sizeof(serial_tmp), NULL))) 73 goto error; 74 if (!(BN_to_ASN1_INTEGER(serial_number, X509_get_serialNumber(x509)))) 75 goto error; 76 } 77 78 if (!(name = tor_x509_name_new(cname))) 79 goto error; 80 if (!(X509_set_subject_name(x509, name))) 81 goto error; 82 if (!(name_issuer = tor_x509_name_new(cname_sign))) 83 goto error; 84 if (!(X509_set_issuer_name(x509, name_issuer))) 85 goto error; 86 87 if (!X509_time_adj(X509_get_notBefore(x509),0,&start_time)) 88 goto error; 89 if (!X509_time_adj(X509_get_notAfter(x509),0,&end_time)) 90 goto error; 91 if (!X509_set_pubkey(x509, pkey)) 92 goto error; 93 94 if (!X509_sign(x509, sign_pkey, EVP_sha256())) 95 goto error; 96 97 goto done; 98 error: 99 fprintf(stderr, "Error making certificate\n"); 100 if (x509) { 101 X509_free(x509); 102 x509 = NULL; 103 } 104 done: 105 if (serial_number) 106 BN_clear_free(serial_number); 107 if (name) 108 X509_NAME_free(name); 109 if (name_issuer) 110 X509_NAME_free(name_issuer); 111 return x509; 112 113 #undef SERIAL_NUMBER_SIZE 114 } 115 116 117 118 int 119 main(int argc, char **argv) 120 { 121 OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL); 122 123 EVP_PKEY *link = NULL, *sign = NULL; 124 EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL); 125 assert(ctx); 126 127 if (EVP_PKEY_keygen_init(ctx) <= 0) { 128 puts("BLAH"); 129 return 1; 130 } 131 EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, 2048); 132 133 int r1 = EVP_PKEY_keygen(ctx, &link); 134 int r2 = EVP_PKEY_keygen(ctx, &sign); 135 assert(r1 == 1 && r2 == 1); 136 137 X509* x509 = tor_tls_create_certificate(link, 138 sign, 139 "Hello", 140 "World", 141 86400); 142 if (!x509) { 143 return 1; 144 } 145 146 FILE *key = fopen("test.key", "w"); 147 int r3 = PEM_write_PrivateKey(key, link, NULL, NULL, 0 , NULL, NULL); 148 assert(r3 == 1); 149 fclose(key); 150 151 FILE *cert = fopen("test.crt", "w"); 152 int r4 = PEM_write_X509(cert, x509); 153 assert(r4 == 1); 154 fclose(cert); 155 156 puts("OK."); 157 158 return 0; 159 }