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;
}

Reply via email to