arti/crates/tor-rtcompat/test-data-generator/make-cert.c

160 lines
4.0 KiB
C

// 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <openssl/opensslv.h>
#include <openssl/err.h>
#include <openssl/asn1.h>
#include <openssl/bio.h>
#include <openssl/bn.h>
#include <openssl/evp.h>
#include <openssl/objects.h>
#include <openssl/rand.h>
#include <openssl/rsa.h>
#include <openssl/ssl.h>
#include <openssl/x509.h>
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;
}