Okay I give up I'm trying to write a program that creates a key and certificate request, and then signs it given a CA (yes it will prompt for passwords and stuff). I'm having big problems though. X509_REQ_verify() on the request and its key returns "21878:error:0D07908D:asn1 encoding routines:ASN1_verify:unknown message digest algorithm:a_verify.c:86:" It works fine signing the request with 'openssl ca' but my stuff doesn't work. I attached the relevant code, any suggestions are welcome! Martin -- Martin Sjögren [EMAIL PROTECTED] ICQ : 41245059 Phone: +46 (0)31 405242 Cell: +46 (0)739 169191 GPG key: http://www.strakt.com/~martin/gpg.html
#include <openssl/x509.h> #include <openssl/x509v3.h> #include <openssl/pem.h> #include <openssl/err.h> #define TYPE_RSA 1 #define TYPE_DSA 2 #define TYPE_DH 3 struct nameinfo { char * common_name; }; extern EVP_PKEY *generate_private_key(int, int); extern X509_REQ *generate_certificate_request(EVP_PKEY *, struct nameinfo *); extern X509 *self_sign_request(X509_REQ *, EVP_PKEY *, EVP_MD *, int); extern X509 *sign_certificate(X509_REQ *, EVP_PKEY *, X509 *, int, EVP_MD *); #define HANDLE_ERROR do { \ fprintf(stderr, "%s:%d\n", __FILE__, __LINE__); \ ERR_print_errors_fp(stderr); \ exit(1); \ } while (0) EVP_PKEY * generate_private_key(int pkey_type, int bits) { EVP_PKEY *pkey; if ((pkey = EVP_PKEY_new()) == NULL) return NULL; switch (pkey_type) { case TYPE_DSA: /* not implemented */ return NULL; case TYPE_DH: /* not implemented */ return NULL; case TYPE_RSA: default: /* RSA is default */ if (!EVP_PKEY_assign_RSA(pkey, RSA_generate_key(bits, 0x10001, NULL, NULL))) { EVP_PKEY_free(pkey); return NULL; } break; } return pkey; } X509_REQ * generate_certificate_request(EVP_PKEY *pkey, struct nameinfo *name) { X509_REQ *req; X509_NAME *subj; if ((req = X509_REQ_new()) == NULL) { return NULL; } if ((subj = X509_REQ_get_subject_name(req)) == NULL) { X509_REQ_free(req); return NULL; } if (!X509_NAME_add_entry_by_NID(subj, NID_commonName, MBSTRING_ASC, name->common_name, -1, -1, 0)) { X509_REQ_free(req); return NULL; } /* ... */ if (!X509_REQ_set_pubkey(req, pkey)) { X509_REQ_free(req); return NULL; } return req; } X509 * self_sign_request(X509_REQ *req, EVP_PKEY *pkey, EVP_MD *digest, int days) { EVP_PKEY *tmppkey = NULL; X509V3_CTX ext_ctx; X509 *x509ss = X509_new(); /* version 3 */ if (!X509_set_version(x509ss, 2)) HANDLE_ERROR; /* serial number 0? */ if (!ASN1_INTEGER_set(X509_get_serialNumber(x509ss), 0L)) HANDLE_ERROR; /* let issuer == subject */ if (!X509_set_issuer_name(x509ss, X509_REQ_get_subject_name(req))) HANDLE_ERROR; if (!X509_gmtime_adj(X509_get_notBefore(x509ss), 0)) HANDLE_ERROR; if (!X509_gmtime_adj(X509_get_notAfter(x509ss), (long)60*60*24*days)) HANDLE_ERROR; /* set subject */ if (!X509_set_subject_name(x509ss, X509_REQ_get_subject_name(req))) HANDLE_ERROR; /* public key */ if ((tmppkey = X509_REQ_get_pubkey(req)) == NULL) HANDLE_ERROR; if (!X509_set_pubkey(x509ss, tmppkey)) HANDLE_ERROR; EVP_PKEY_free(tmppkey); tmppkey = NULL; /* X509V3 stuff */ X509V3_set_ctx(&ext_ctx, x509ss, x509ss, NULL, NULL, 0); /* sign */ if (digest == NULL) digest = EVP_md5(); if (!X509_sign(x509ss, pkey, digest)) HANDLE_ERROR; return x509ss; error: X509_free(x509ss); if (tmppkey != NULL) EVP_PKEY_free(tmppkey); return NULL; } // newreq=1 x509=0 X509 * sign_certificate(X509_REQ *req, EVP_PKEY *ca_pkey, X509 *ca_cert, int days, EVP_MD *digest) { X509 *cert = NULL; EVP_PKEY *req_key = NULL; X509_REQ_print_fp(stderr, req); if ((req_key = X509_REQ_get_pubkey(req)) == NULL) HANDLE_ERROR; if (X509_REQ_verify(req, req_key) <= 0) HANDLE_ERROR; EVP_PKEY_free(req_key); req_key = NULL; /* should check the req here? */ if ((cert = X509_new()) == NULL) HANDLE_ERROR; if (!X509_set_version(ca_cert, 2)) HANDLE_ERROR; /* SERIAL NUMBER HERE */ X509_gmtime_adj(X509_get_notBefore(cert), 0); X509_gmtime_adj(X509_get_notAfter(cert), (long)60*60*24*days); if (!X509_set_issuer_name(cert, X509_get_subject_name(ca_cert))) HANDLE_ERROR; if (!X509_set_subject_name(cert, X509_REQ_get_subject_name(req))) HANDLE_ERROR; req_key = X509_REQ_get_pubkey(req); if (!X509_set_pubkey(cert, req_key)) HANDLE_ERROR; EVP_PKEY_free(req_key); req_key = NULL; /* sign */ if (digest == NULL) digest = EVP_md5(); if (!X509_sign(cert, ca_pkey, digest)) HANDLE_ERROR; return cert; error: if (req_key != NULL) EVP_PKEY_free(req_key); if (cert != NULL) X509_free(cert); return NULL; } int main(int argc, char *argv[]) { EVP_PKEY *pkey; X509_REQ *req; char *cakey_fname, *cacert_fname, *keyout_fname, *csrout_fname, *certout_fname; int days, bits = 1024; if (argc != 7) { fprintf(stderr, "Syntax: %s cakey cacert keyout csrout certout days\n", argv[0]); exit(1); } cakey_fname = argv[1]; cacert_fname = argv[2]; keyout_fname = argv[3]; csrout_fname = argv[4]; certout_fname = argv[5]; days = atoi(argv[6]); ERR_load_crypto_strings(); /* * INIT PRNG */ while (!RAND_status()) RAND_load_file("/dev/urandom", 256); /* * GENERATE AN RSA PRIVATE KEY */ { BIO *out = BIO_new_file(keyout_fname, "w"); EVP_CIPHER *cipher = NULL; //EVP_des_ede3_cbc(); if ((pkey = generate_private_key(TYPE_RSA, bits)) == NULL) HANDLE_ERROR; // "foo" is the pass phrase (?) if (!PEM_write_bio_PrivateKey(out, pkey, cipher, NULL, 0, NULL, "foo")) HANDLE_ERROR; BIO_free(out); } /* * GENERATE A CERT REQUEST */ { struct nameinfo info = { "Olle i skogen" }; X509V3_CTX ext_ctx; BIO *out; if ((req = generate_certificate_request(pkey, &info)) == NULL) HANDLE_ERROR; X509V3_set_ctx(&ext_ctx, NULL, NULL, req, NULL, 0); if (!X509_REQ_sign(req, pkey, EVP_md5())) HANDLE_ERROR; out = BIO_new_file(csrout_fname, "w"); PEM_write_bio_X509_REQ(out, req); BIO_free(out); } /* * SIGN THE REQUEST */ { X509 *cacert, *cert; EVP_PKEY *cakey; BIO *out, *temp; temp = BIO_new_file(cakey_fname, "r"); /* "foo" is the password for the CA (?) */ if ((cakey = PEM_read_bio_PrivateKey(temp, NULL, NULL, "foo")) == NULL) HANDLE_ERROR; BIO_free(temp); temp = BIO_new_file(cacert_fname, "r"); if ((cacert = PEM_read_bio_X509(temp, NULL, NULL, NULL)) == NULL) HANDLE_ERROR; BIO_free(temp); if ((cert = sign_certificate(req, cakey, cacert, days, EVP_md5()))) HANDLE_ERROR; out = BIO_new_file(certout_fname, "w"); PEM_write_bio_X509(out, cert); BIO_free(out); } return 0; error: ERR_print_errors_fp(stderr); return 1; }