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  }