Blame modules/md/md_crypt.c

Packit 90a5c9
/* Licensed to the Apache Software Foundation (ASF) under one or more
Packit 90a5c9
 * contributor license agreements.  See the NOTICE file distributed with
Packit 90a5c9
 * this work for additional information regarding copyright ownership.
Packit 90a5c9
 * The ASF licenses this file to You under the Apache License, Version 2.0
Packit 90a5c9
 * (the "License"); you may not use this file except in compliance with
Packit 90a5c9
 * the License.  You may obtain a copy of the License at
Packit 90a5c9
 *
Packit 90a5c9
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 90a5c9
 *
Packit 90a5c9
 * Unless required by applicable law or agreed to in writing, software
Packit 90a5c9
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 90a5c9
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 90a5c9
 * See the License for the specific language governing permissions and
Packit 90a5c9
 * limitations under the License.
Packit 90a5c9
 */
Packit 90a5c9
 
Packit 90a5c9
#include <assert.h>
Packit 90a5c9
#include <stdio.h>
Packit 90a5c9
#include <stdlib.h>
Packit 90a5c9
Packit 90a5c9
#include <apr_lib.h>
Packit 90a5c9
#include <apr_buckets.h>
Packit 90a5c9
#include <apr_file_io.h>
Packit 90a5c9
#include <apr_strings.h>
Packit 90a5c9
Packit 90a5c9
#include <openssl/err.h>
Packit 90a5c9
#include <openssl/evp.h>
Packit 90a5c9
#include <openssl/pem.h>
Packit 90a5c9
#include <openssl/rand.h>
Packit 90a5c9
#include <openssl/rsa.h>
Packit 90a5c9
#include <openssl/x509v3.h>
Packit 90a5c9
Packit 90a5c9
#include "md.h"
Packit 90a5c9
#include "md_crypt.h"
Packit 90a5c9
#include "md_json.h"
Packit 90a5c9
#include "md_log.h"
Packit 90a5c9
#include "md_http.h"
Packit 90a5c9
#include "md_util.h"
Packit 90a5c9
Packit 90a5c9
/* getpid for *NIX */
Packit 90a5c9
#if APR_HAVE_SYS_TYPES_H
Packit 90a5c9
#include <sys/types.h>
Packit 90a5c9
#endif
Packit 90a5c9
#if APR_HAVE_UNISTD_H
Packit 90a5c9
#include <unistd.h>
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
/* getpid for Windows */
Packit 90a5c9
#if APR_HAVE_PROCESS_H
Packit 90a5c9
#include <process.h>
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
#if defined(LIBRESSL_VERSION_NUMBER)
Packit 90a5c9
/* Missing from LibreSSL */
Packit 90a5c9
#define MD_USE_OPENSSL_PRE_1_1_API (LIBRESSL_VERSION_NUMBER < 0x2070000f)
Packit 90a5c9
#else /* defined(LIBRESSL_VERSION_NUMBER) */
Packit 90a5c9
#define MD_USE_OPENSSL_PRE_1_1_API (OPENSSL_VERSION_NUMBER < 0x10100000L)
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
static int initialized;
Packit 90a5c9
Packit 90a5c9
struct md_pkey_t {
Packit 90a5c9
    apr_pool_t *pool;
Packit 90a5c9
    EVP_PKEY   *pkey;
Packit 90a5c9
};
Packit 90a5c9
Packit 90a5c9
#ifdef MD_HAVE_ARC4RANDOM
Packit 90a5c9
Packit 90a5c9
static void seed_RAND(int pid)
Packit 90a5c9
{
Packit 90a5c9
    char seed[128];
Packit 90a5c9
    
Packit 90a5c9
    (void)pid;
Packit 90a5c9
    arc4random_buf(seed, sizeof(seed));
Packit 90a5c9
    RAND_seed(seed, sizeof(seed));
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
#else /* ifdef MD_HAVE_ARC4RANDOM */
Packit 90a5c9
Packit 90a5c9
static int rand_choosenum(int l, int h)
Packit 90a5c9
{
Packit 90a5c9
    int i;
Packit 90a5c9
    char buf[50];
Packit 90a5c9
Packit 90a5c9
    apr_snprintf(buf, sizeof(buf), "%.0f",
Packit 90a5c9
                 (((double)(rand()%RAND_MAX)/RAND_MAX)*(h-l)));
Packit 90a5c9
    i = atoi(buf)+1;
Packit 90a5c9
    if (i < l) i = l;
Packit 90a5c9
    if (i > h) i = h;
Packit 90a5c9
    return i;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static void seed_RAND(int pid)
Packit 90a5c9
{   
Packit 90a5c9
    unsigned char stackdata[256];
Packit 90a5c9
    /* stolen from mod_ssl/ssl_engine_rand.c */
Packit 90a5c9
    int n;
Packit 90a5c9
    struct {
Packit 90a5c9
        time_t t;
Packit 90a5c9
        pid_t pid;
Packit 90a5c9
    } my_seed;
Packit 90a5c9
    
Packit 90a5c9
    /*
Packit 90a5c9
     * seed in the current time (usually just 4 bytes)
Packit 90a5c9
     */
Packit 90a5c9
    my_seed.t = time(NULL);
Packit 90a5c9
    
Packit 90a5c9
    /*
Packit 90a5c9
     * seed in the current process id (usually just 4 bytes)
Packit 90a5c9
     */
Packit 90a5c9
    my_seed.pid = pid;
Packit 90a5c9
    
Packit 90a5c9
    RAND_seed((unsigned char *)&my_seed, sizeof(my_seed));
Packit 90a5c9
    
Packit 90a5c9
    /*
Packit 90a5c9
     * seed in some current state of the run-time stack (128 bytes)
Packit 90a5c9
     */
Packit 90a5c9
    n = rand_choosenum(0, sizeof(stackdata)-128-1);
Packit 90a5c9
    RAND_seed(stackdata+n, 128);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
#endif /*ifdef MD_HAVE_ARC4RANDOM (else part) */
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
apr_status_t md_crypt_init(apr_pool_t *pool)
Packit 90a5c9
{
Packit 90a5c9
    (void)pool;
Packit 90a5c9
    
Packit 90a5c9
    if (!initialized) {
Packit 90a5c9
        int pid = getpid();
Packit 90a5c9
        
Packit 90a5c9
        ERR_load_crypto_strings();
Packit 90a5c9
        OpenSSL_add_all_algorithms();
Packit 90a5c9
        
Packit 90a5c9
        md_log_perror(MD_LOG_MARK, MD_LOG_TRACE2, 0, pool, "initializing RAND"); 
Packit 90a5c9
        while (!RAND_status()) {
Packit 90a5c9
            seed_RAND(pid);
Packit 90a5c9
	}
Packit 90a5c9
Packit 90a5c9
        initialized = 1;
Packit 90a5c9
    }
Packit 90a5c9
    return APR_SUCCESS;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
typedef struct {
Packit 90a5c9
    char *data;
Packit 90a5c9
    apr_size_t len;
Packit 90a5c9
} buffer_rec;
Packit 90a5c9
Packit 90a5c9
static apr_status_t fwrite_buffer(void *baton, apr_file_t *f, apr_pool_t *p) 
Packit 90a5c9
{
Packit 90a5c9
    buffer_rec *buf = baton;
Packit 90a5c9
    
Packit 90a5c9
    (void)p;
Packit 90a5c9
    return apr_file_write_full(f, buf->data, buf->len, &buf->len);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
apr_status_t md_rand_bytes(unsigned char *buf, apr_size_t len, apr_pool_t *p)
Packit 90a5c9
{
Packit 90a5c9
    apr_status_t rv;
Packit 90a5c9
    
Packit 90a5c9
    if (len > INT_MAX) {
Packit 90a5c9
        return APR_ENOTIMPL;
Packit 90a5c9
    }
Packit 90a5c9
    if (APR_SUCCESS == (rv = md_crypt_init(p))) {
Packit 90a5c9
        RAND_bytes((unsigned char*)buf, (int)len);
Packit 90a5c9
    }
Packit 90a5c9
    return rv;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
typedef struct {
Packit 90a5c9
    const char *pass_phrase;
Packit 90a5c9
    int pass_len;
Packit 90a5c9
} passwd_ctx;
Packit 90a5c9
Packit 90a5c9
static int pem_passwd(char *buf, int size, int rwflag, void *baton)
Packit 90a5c9
{
Packit 90a5c9
    passwd_ctx *ctx = baton;
Packit 90a5c9
    
Packit 90a5c9
    (void)rwflag;
Packit 90a5c9
    if (ctx->pass_len > 0) {
Packit 90a5c9
        if (ctx->pass_len < size) {
Packit 90a5c9
            size = (int)ctx->pass_len;
Packit 90a5c9
        }
Packit 90a5c9
        memcpy(buf, ctx->pass_phrase, (size_t)size);
Packit 90a5c9
    }
Packit 90a5c9
    return ctx->pass_len;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/**************************************************************************************************/
Packit 90a5c9
/* date time things */
Packit 90a5c9
Packit 90a5c9
/* Get the apr time (micro seconds, since 1970) from an ASN1 time, as stored in X509
Packit 90a5c9
 * certificates. OpenSSL now has a utility function, but other *SSL derivatives have
Packit 90a5c9
 * not caughts up yet or chose to ignore. An alternative is implemented, we prefer 
Packit 90a5c9
 * however the *SSL to maintain such things.
Packit 90a5c9
 */
Packit 90a5c9
static apr_time_t md_asn1_time_get(const ASN1_TIME* time)
Packit 90a5c9
{
Packit 90a5c9
#if OPENSSL_VERSION_NUMBER < 0x10002000L || defined(LIBRESSL_VERSION_NUMBER)
Packit 90a5c9
    /* courtesy: https://stackoverflow.com/questions/10975542/asn1-time-to-time-t-conversion#11263731
Packit 90a5c9
     * all bugs are mine */
Packit 90a5c9
    apr_time_exp_t t;
Packit 90a5c9
    apr_time_t ts;
Packit 90a5c9
    const char* str = (const char*) time->data;
Packit 90a5c9
    apr_size_t i = 0;
Packit 90a5c9
Packit 90a5c9
    memset(&t, 0, sizeof(t));
Packit 90a5c9
Packit 90a5c9
    if (time->type == V_ASN1_UTCTIME) {/* two digit year */
Packit 90a5c9
        t.tm_year = (str[i++] - '0') * 10;
Packit 90a5c9
        t.tm_year += (str[i++] - '0');
Packit 90a5c9
        if (t.tm_year < 70)
Packit 90a5c9
            t.tm_year += 100;
Packit 90a5c9
    } 
Packit 90a5c9
    else if (time->type == V_ASN1_GENERALIZEDTIME) {/* four digit year */
Packit 90a5c9
        t.tm_year = (str[i++] - '0') * 1000;
Packit 90a5c9
        t.tm_year+= (str[i++] - '0') * 100;
Packit 90a5c9
        t.tm_year+= (str[i++] - '0') * 10;
Packit 90a5c9
        t.tm_year+= (str[i++] - '0');
Packit 90a5c9
        t.tm_year -= 1900;
Packit 90a5c9
    }
Packit 90a5c9
    t.tm_mon  = (str[i++] - '0') * 10;
Packit 90a5c9
    t.tm_mon += (str[i++] - '0') - 1; /* -1 since January is 0 not 1. */
Packit 90a5c9
    t.tm_mday = (str[i++] - '0') * 10;
Packit 90a5c9
    t.tm_mday+= (str[i++] - '0');
Packit 90a5c9
    t.tm_hour = (str[i++] - '0') * 10;
Packit 90a5c9
    t.tm_hour+= (str[i++] - '0');
Packit 90a5c9
    t.tm_min  = (str[i++] - '0') * 10;
Packit 90a5c9
    t.tm_min += (str[i++] - '0');
Packit 90a5c9
    t.tm_sec  = (str[i++] - '0') * 10;
Packit 90a5c9
    t.tm_sec += (str[i++] - '0');
Packit 90a5c9
    
Packit 90a5c9
    if (APR_SUCCESS == apr_time_exp_gmt_get(&ts, &t)) {
Packit 90a5c9
        return ts;
Packit 90a5c9
    }
Packit 90a5c9
    return 0;
Packit 90a5c9
#else 
Packit 90a5c9
    int secs, days;
Packit 90a5c9
    apr_time_t ts = apr_time_now();
Packit 90a5c9
    
Packit 90a5c9
    if (ASN1_TIME_diff(&days, &secs, NULL, time)) {
Packit 90a5c9
        ts += apr_time_from_sec((days * MD_SECS_PER_DAY) + secs); 
Packit 90a5c9
    }
Packit 90a5c9
    return ts;
Packit 90a5c9
#endif
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
/**************************************************************************************************/
Packit 90a5c9
/* private keys */
Packit 90a5c9
Packit 90a5c9
md_json_t *md_pkey_spec_to_json(const md_pkey_spec_t *spec, apr_pool_t *p)
Packit 90a5c9
{
Packit 90a5c9
    md_json_t *json = md_json_create(p);
Packit 90a5c9
    if (json) {
Packit 90a5c9
        switch (spec->type) {
Packit 90a5c9
            case MD_PKEY_TYPE_DEFAULT:
Packit 90a5c9
                md_json_sets("Default", json, MD_KEY_TYPE, NULL);
Packit 90a5c9
                break;
Packit 90a5c9
            case MD_PKEY_TYPE_RSA:
Packit 90a5c9
                md_json_sets("RSA", json, MD_KEY_TYPE, NULL);
Packit 90a5c9
                if (spec->params.rsa.bits >= MD_PKEY_RSA_BITS_MIN) {
Packit 90a5c9
                    md_json_setl((long)spec->params.rsa.bits, json, MD_KEY_BITS, NULL);
Packit 90a5c9
                }
Packit 90a5c9
                break;
Packit 90a5c9
            default:
Packit 90a5c9
                md_json_sets("Unsupported", json, MD_KEY_TYPE, NULL);
Packit 90a5c9
                break;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    return json;    
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
md_pkey_spec_t *md_pkey_spec_from_json(struct md_json_t *json, apr_pool_t *p)
Packit 90a5c9
{
Packit 90a5c9
    md_pkey_spec_t *spec = apr_pcalloc(p, sizeof(*spec));
Packit 90a5c9
    const char *s;
Packit 90a5c9
    long l;
Packit 90a5c9
    
Packit 90a5c9
    if (spec) {
Packit 90a5c9
        s = md_json_gets(json, MD_KEY_TYPE, NULL);
Packit 90a5c9
        if (!s || !apr_strnatcasecmp("Default", s)) {
Packit 90a5c9
            spec->type = MD_PKEY_TYPE_DEFAULT;
Packit 90a5c9
        }
Packit 90a5c9
        else if (!apr_strnatcasecmp("RSA", s)) {
Packit 90a5c9
            spec->type = MD_PKEY_TYPE_RSA;
Packit 90a5c9
            l = md_json_getl(json, MD_KEY_BITS, NULL);
Packit 90a5c9
            if (l >= MD_PKEY_RSA_BITS_MIN) {
Packit 90a5c9
                spec->params.rsa.bits = (unsigned int)l;
Packit 90a5c9
            }
Packit 90a5c9
            else {
Packit 90a5c9
                spec->params.rsa.bits = MD_PKEY_RSA_BITS_DEF;
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    return spec;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
int md_pkey_spec_eq(md_pkey_spec_t *spec1, md_pkey_spec_t *spec2)
Packit 90a5c9
{
Packit 90a5c9
    if (spec1 == spec2) {
Packit 90a5c9
        return 1;
Packit 90a5c9
    }
Packit 90a5c9
    if (spec1 && spec2 && spec1->type == spec2->type) {
Packit 90a5c9
        switch (spec1->type) {
Packit 90a5c9
            case MD_PKEY_TYPE_DEFAULT:
Packit 90a5c9
                return 1;
Packit 90a5c9
            case MD_PKEY_TYPE_RSA:
Packit 90a5c9
                if (spec1->params.rsa.bits == spec2->params.rsa.bits) {
Packit 90a5c9
                    return 1;
Packit 90a5c9
                }
Packit 90a5c9
                break;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    return 0;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static md_pkey_t *make_pkey(apr_pool_t *p) 
Packit 90a5c9
{
Packit 90a5c9
    md_pkey_t *pkey = apr_pcalloc(p, sizeof(*pkey));
Packit 90a5c9
    pkey->pool = p;
Packit 90a5c9
    return pkey;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static apr_status_t pkey_cleanup(void *data)
Packit 90a5c9
{
Packit 90a5c9
    md_pkey_t *pkey = data;
Packit 90a5c9
    if (pkey->pkey) {
Packit 90a5c9
        EVP_PKEY_free(pkey->pkey);
Packit 90a5c9
        pkey->pkey = NULL;
Packit 90a5c9
    }
Packit 90a5c9
    return APR_SUCCESS;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
void md_pkey_free(md_pkey_t *pkey)
Packit 90a5c9
{
Packit 90a5c9
    pkey_cleanup(pkey);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
void *md_pkey_get_EVP_PKEY(struct md_pkey_t *pkey)
Packit 90a5c9
{
Packit 90a5c9
    return pkey->pkey;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
apr_status_t md_pkey_fload(md_pkey_t **ppkey, apr_pool_t *p, 
Packit 90a5c9
                           const char *key, apr_size_t key_len,
Packit 90a5c9
                           const char *fname)
Packit 90a5c9
{
Packit 90a5c9
    apr_status_t rv = APR_ENOENT;
Packit 90a5c9
    md_pkey_t *pkey;
Packit 90a5c9
    BIO *bf;
Packit 90a5c9
    passwd_ctx ctx;
Packit 90a5c9
    
Packit 90a5c9
    pkey =  make_pkey(p);
Packit 90a5c9
    if (NULL != (bf = BIO_new_file(fname, "r"))) {
Packit 90a5c9
        ctx.pass_phrase = key;
Packit 90a5c9
        ctx.pass_len = (int)key_len;
Packit 90a5c9
        
Packit 90a5c9
        ERR_clear_error();
Packit 90a5c9
        pkey->pkey = PEM_read_bio_PrivateKey(bf, NULL, pem_passwd, &ctx;;
Packit 90a5c9
        BIO_free(bf);
Packit 90a5c9
        
Packit 90a5c9
        if (pkey->pkey != NULL) {
Packit 90a5c9
            rv = APR_SUCCESS;
Packit 90a5c9
            apr_pool_cleanup_register(p, pkey, pkey_cleanup, apr_pool_cleanup_null);
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            unsigned long err = ERR_get_error();
Packit 90a5c9
            rv = APR_EINVAL;
Packit 90a5c9
            md_log_perror(MD_LOG_MARK, MD_LOG_WARNING, rv, p, 
Packit 90a5c9
                          "error loading pkey %s: %s (pass phrase was %snull)", fname,
Packit 90a5c9
                          ERR_error_string(err, NULL), key? "not " : ""); 
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    *ppkey = (APR_SUCCESS == rv)? pkey : NULL;
Packit 90a5c9
    return rv;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static apr_status_t pkey_to_buffer(buffer_rec *buffer, md_pkey_t *pkey, apr_pool_t *p,
Packit 90a5c9
                                   const char *pass, apr_size_t pass_len)
Packit 90a5c9
{
Packit 90a5c9
    BIO *bio = BIO_new(BIO_s_mem());
Packit 90a5c9
    const EVP_CIPHER *cipher = NULL;
Packit 90a5c9
    pem_password_cb *cb = NULL;
Packit 90a5c9
    void *cb_baton = NULL;
Packit 90a5c9
    passwd_ctx ctx;
Packit 90a5c9
    unsigned long err;
Packit 90a5c9
    int i;
Packit 90a5c9
    
Packit 90a5c9
    if (!bio) {
Packit 90a5c9
        return APR_ENOMEM;
Packit 90a5c9
    }
Packit 90a5c9
    if (pass_len > INT_MAX) {
Packit 90a5c9
        return APR_EINVAL;
Packit 90a5c9
    }
Packit 90a5c9
    if (pass && pass_len > 0) {
Packit 90a5c9
        ctx.pass_phrase = pass;
Packit 90a5c9
        ctx.pass_len = (int)pass_len;
Packit 90a5c9
        cb = pem_passwd;
Packit 90a5c9
        cb_baton = &ctx;
Packit 90a5c9
        cipher = EVP_aes_256_cbc();
Packit 90a5c9
        if (!cipher) {
Packit 90a5c9
            return APR_ENOTIMPL;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    
Packit 90a5c9
    ERR_clear_error();
Packit 90a5c9
    if (!PEM_write_bio_PrivateKey(bio, pkey->pkey, cipher, NULL, 0, cb, cb_baton)) {
Packit 90a5c9
        BIO_free(bio);
Packit 90a5c9
        err = ERR_get_error();
Packit 90a5c9
        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, "PEM_write key: %ld %s", 
Packit 90a5c9
                      err, ERR_error_string(err, NULL)); 
Packit 90a5c9
        return APR_EINVAL;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    i = BIO_pending(bio);
Packit 90a5c9
    if (i > 0) {
Packit 90a5c9
        buffer->data = apr_palloc(p, (apr_size_t)i + 1);
Packit 90a5c9
        i = BIO_read(bio, buffer->data, i);
Packit 90a5c9
        buffer->data[i] = '\0';
Packit 90a5c9
        buffer->len = (apr_size_t)i;
Packit 90a5c9
    }
Packit 90a5c9
    BIO_free(bio);
Packit 90a5c9
    return APR_SUCCESS;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
apr_status_t md_pkey_fsave(md_pkey_t *pkey, apr_pool_t *p, 
Packit 90a5c9
                           const char *pass_phrase, apr_size_t pass_len,
Packit 90a5c9
                           const char *fname, apr_fileperms_t perms)
Packit 90a5c9
{
Packit 90a5c9
    buffer_rec buffer;
Packit 90a5c9
    apr_status_t rv;
Packit 90a5c9
    
Packit 90a5c9
    if (APR_SUCCESS == (rv = pkey_to_buffer(&buffer, pkey, p, pass_phrase, pass_len))) {
Packit 90a5c9
        return md_util_freplace(fname, perms, p, fwrite_buffer, &buffer); 
Packit 90a5c9
    }
Packit 90a5c9
    md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, p, "save pkey %s (%s pass phrase, len=%d)",
Packit 90a5c9
                  fname, pass_len > 0? "with" : "without", (int)pass_len); 
Packit 90a5c9
    return rv;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static apr_status_t gen_rsa(md_pkey_t **ppkey, apr_pool_t *p, unsigned int bits)
Packit 90a5c9
{
Packit 90a5c9
    EVP_PKEY_CTX *ctx = NULL;
Packit 90a5c9
    apr_status_t rv;
Packit 90a5c9
    
Packit 90a5c9
    *ppkey = make_pkey(p);
Packit 90a5c9
    ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
Packit 90a5c9
    if (ctx 
Packit 90a5c9
        && EVP_PKEY_keygen_init(ctx) >= 0
Packit 90a5c9
        && EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, (int)bits) >= 0
Packit 90a5c9
        && EVP_PKEY_keygen(ctx, &(*ppkey)->pkey) >= 0) {
Packit 90a5c9
        rv = APR_SUCCESS;
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        md_log_perror(MD_LOG_MARK, MD_LOG_WARNING, 0, p, "error generate pkey RSA %d", bits); 
Packit 90a5c9
        *ppkey = NULL;
Packit 90a5c9
        rv = APR_EGENERAL;
Packit 90a5c9
    }
Packit 90a5c9
    
Packit 90a5c9
    if (ctx != NULL) {
Packit 90a5c9
        EVP_PKEY_CTX_free(ctx);
Packit 90a5c9
    }
Packit 90a5c9
    return rv;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
apr_status_t md_pkey_gen(md_pkey_t **ppkey, apr_pool_t *p, md_pkey_spec_t *spec)
Packit 90a5c9
{
Packit 90a5c9
    md_pkey_type_t ptype = spec? spec->type : MD_PKEY_TYPE_DEFAULT;
Packit 90a5c9
    switch (ptype) {
Packit 90a5c9
        case MD_PKEY_TYPE_DEFAULT:
Packit 90a5c9
            return gen_rsa(ppkey, p, MD_PKEY_RSA_BITS_DEF);
Packit 90a5c9
        case MD_PKEY_TYPE_RSA:
Packit 90a5c9
            return gen_rsa(ppkey, p, spec->params.rsa.bits);
Packit 90a5c9
        default:
Packit 90a5c9
            return APR_ENOTIMPL;
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
#if MD_USE_OPENSSL_PRE_1_1_API || (defined(LIBRESSL_VERSION_NUMBER) && \
Packit 90a5c9
                                   LIBRESSL_VERSION_NUMBER < 0x2070000f)
Packit 90a5c9
Packit 90a5c9
#ifndef NID_tlsfeature
Packit 90a5c9
#define NID_tlsfeature          1020
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
static void RSA_get0_key(const RSA *r,
Packit 90a5c9
                         const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
Packit 90a5c9
{
Packit 90a5c9
    if (n != NULL)
Packit 90a5c9
        *n = r->n;
Packit 90a5c9
    if (e != NULL)
Packit 90a5c9
        *e = r->e;
Packit 90a5c9
    if (d != NULL)
Packit 90a5c9
        *d = r->d;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
static const char *bn64(const BIGNUM *b, apr_pool_t *p) 
Packit 90a5c9
{
Packit 90a5c9
    if (b) {
Packit 90a5c9
         apr_size_t len = (apr_size_t)BN_num_bytes(b);
Packit 90a5c9
         char *buffer = apr_pcalloc(p, len);
Packit 90a5c9
         if (buffer) {
Packit 90a5c9
            BN_bn2bin(b, (unsigned char *)buffer);
Packit 90a5c9
            return md_util_base64url_encode(buffer, len, p);
Packit 90a5c9
         }
Packit 90a5c9
    }
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
const char *md_pkey_get_rsa_e64(md_pkey_t *pkey, apr_pool_t *p)
Packit 90a5c9
{
Packit 90a5c9
    const BIGNUM *e;
Packit 90a5c9
    RSA *rsa = EVP_PKEY_get1_RSA(pkey->pkey);
Packit 90a5c9
    
Packit 90a5c9
    if (!rsa) {
Packit 90a5c9
        return NULL;
Packit 90a5c9
    }
Packit 90a5c9
    RSA_get0_key(rsa, NULL, &e, NULL);
Packit 90a5c9
    return bn64(e, p);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
const char *md_pkey_get_rsa_n64(md_pkey_t *pkey, apr_pool_t *p)
Packit 90a5c9
{
Packit 90a5c9
    const BIGNUM *n;
Packit 90a5c9
    RSA *rsa = EVP_PKEY_get1_RSA(pkey->pkey);
Packit 90a5c9
    
Packit 90a5c9
    if (!rsa) {
Packit 90a5c9
        return NULL;
Packit 90a5c9
    }
Packit 90a5c9
    RSA_get0_key(rsa, &n, NULL, NULL);
Packit 90a5c9
    return bn64(n, p);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
apr_status_t md_crypt_sign64(const char **psign64, md_pkey_t *pkey, apr_pool_t *p, 
Packit 90a5c9
                             const char *d, size_t dlen)
Packit 90a5c9
{
Packit 90a5c9
    EVP_MD_CTX *ctx = NULL;
Packit 90a5c9
    char *buffer;
Packit 90a5c9
    unsigned int blen;
Packit 90a5c9
    const char *sign64 = NULL;
Packit 90a5c9
    apr_status_t rv = APR_ENOMEM;
Packit 90a5c9
    
Packit 90a5c9
    buffer = apr_pcalloc(p, (apr_size_t)EVP_PKEY_size(pkey->pkey));
Packit 90a5c9
    if (buffer) {
Packit 90a5c9
        ctx = EVP_MD_CTX_create();
Packit 90a5c9
        if (ctx) {
Packit 90a5c9
            rv = APR_ENOTIMPL;
Packit 90a5c9
            if (EVP_SignInit_ex(ctx, EVP_sha256(), NULL)) {
Packit 90a5c9
                rv = APR_EGENERAL;
Packit 90a5c9
                if (EVP_SignUpdate(ctx, d, dlen)) {
Packit 90a5c9
                    if (EVP_SignFinal(ctx, (unsigned char*)buffer, &blen, pkey->pkey)) {
Packit 90a5c9
                        sign64 = md_util_base64url_encode(buffer, blen, p);
Packit 90a5c9
                        if (sign64) {
Packit 90a5c9
                            rv = APR_SUCCESS;
Packit 90a5c9
                        }
Packit 90a5c9
                    }
Packit 90a5c9
                }
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
        
Packit 90a5c9
        if (ctx) {
Packit 90a5c9
            EVP_MD_CTX_destroy(ctx);
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    
Packit 90a5c9
    if (rv != APR_SUCCESS) {
Packit 90a5c9
        md_log_perror(MD_LOG_MARK, MD_LOG_WARNING, rv, p, "signing"); 
Packit 90a5c9
    }
Packit 90a5c9
    
Packit 90a5c9
    *psign64 = sign64;
Packit 90a5c9
    return rv;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static apr_status_t sha256_digest(unsigned char **pdigest, size_t *pdigest_len,
Packit 90a5c9
                                  apr_pool_t *p, const char *d, size_t dlen)
Packit 90a5c9
{
Packit 90a5c9
    EVP_MD_CTX *ctx = NULL;
Packit 90a5c9
    unsigned char *buffer;
Packit 90a5c9
    apr_status_t rv = APR_ENOMEM;
Packit 90a5c9
    unsigned int blen;
Packit 90a5c9
    
Packit 90a5c9
    buffer = apr_pcalloc(p, EVP_MAX_MD_SIZE);
Packit 90a5c9
    if (buffer) {
Packit 90a5c9
        ctx = EVP_MD_CTX_create();
Packit 90a5c9
        if (ctx) {
Packit 90a5c9
            rv = APR_ENOTIMPL;
Packit 90a5c9
            if (EVP_DigestInit_ex(ctx, EVP_sha256(), NULL)) {
Packit 90a5c9
                rv = APR_EGENERAL;
Packit 90a5c9
                if (EVP_DigestUpdate(ctx, d, dlen)) {
Packit 90a5c9
                    if (EVP_DigestFinal(ctx, buffer, &blen)) {
Packit 90a5c9
                        rv = APR_SUCCESS;
Packit 90a5c9
                    }
Packit 90a5c9
                }
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
        
Packit 90a5c9
        if (ctx) {
Packit 90a5c9
            EVP_MD_CTX_destroy(ctx);
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    
Packit 90a5c9
    if (APR_SUCCESS == rv) {
Packit 90a5c9
        *pdigest = buffer;
Packit 90a5c9
        *pdigest_len = blen;
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        md_log_perror(MD_LOG_MARK, MD_LOG_WARNING, rv, p, "digest"); 
Packit 90a5c9
        *pdigest = NULL;
Packit 90a5c9
        *pdigest_len = 0;
Packit 90a5c9
    }
Packit 90a5c9
    return rv;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
apr_status_t md_crypt_sha256_digest64(const char **pdigest64, apr_pool_t *p, 
Packit 90a5c9
                                      const char *d, size_t dlen)
Packit 90a5c9
{
Packit 90a5c9
    const char *digest64 = NULL;
Packit 90a5c9
    unsigned char *buffer;
Packit 90a5c9
    size_t blen;
Packit 90a5c9
    apr_status_t rv;
Packit 90a5c9
    
Packit 90a5c9
    if (APR_SUCCESS == (rv = sha256_digest(&buffer, &blen, p, d, dlen))) {
Packit 90a5c9
        if (NULL == (digest64 = md_util_base64url_encode((const char*)buffer, blen, p))) {
Packit 90a5c9
            rv = APR_EGENERAL;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    *pdigest64 = digest64;
Packit 90a5c9
    return rv;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char * const hex_const[] = {
Packit 90a5c9
    "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0a", "0b", "0c", "0d", "0e", "0f", 
Packit 90a5c9
    "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1a", "1b", "1c", "1d", "1e", "1f", 
Packit 90a5c9
    "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2a", "2b", "2c", "2d", "2e", "2f", 
Packit 90a5c9
    "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3a", "3b", "3c", "3d", "3e", "3f", 
Packit 90a5c9
    "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4a", "4b", "4c", "4d", "4e", "4f", 
Packit 90a5c9
    "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5a", "5b", "5c", "5d", "5e", "5f", 
Packit 90a5c9
    "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6a", "6b", "6c", "6d", "6e", "6f", 
Packit 90a5c9
    "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7a", "7b", "7c", "7d", "7e", "7f", 
Packit 90a5c9
    "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8a", "8b", "8c", "8d", "8e", "8f", 
Packit 90a5c9
    "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9a", "9b", "9c", "9d", "9e", "9f", 
Packit 90a5c9
    "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "aa", "ab", "ac", "ad", "ae", "af", 
Packit 90a5c9
    "b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7", "b8", "b9", "ba", "bb", "bc", "bd", "be", "bf", 
Packit 90a5c9
    "c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "ca", "cb", "cc", "cd", "ce", "cf", 
Packit 90a5c9
    "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "da", "db", "dc", "dd", "de", "df", 
Packit 90a5c9
    "e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7", "e8", "e9", "ea", "eb", "ec", "ed", "ee", "ef", 
Packit 90a5c9
    "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "fa", "fb", "fc", "fd", "fe", "ff", 
Packit 90a5c9
};
Packit 90a5c9
Packit 90a5c9
apr_status_t md_crypt_sha256_digest_hex(const char **pdigesthex, apr_pool_t *p, 
Packit 90a5c9
                                        const char *d, size_t dlen)
Packit 90a5c9
{
Packit 90a5c9
    char *dhex = NULL, *cp;
Packit 90a5c9
    const char * x;
Packit 90a5c9
    unsigned char *buffer;
Packit 90a5c9
    size_t blen;
Packit 90a5c9
    apr_status_t rv;
Packit 90a5c9
    unsigned int i;
Packit 90a5c9
    
Packit 90a5c9
    if (APR_SUCCESS == (rv = sha256_digest(&buffer, &blen, p, d, dlen))) {
Packit 90a5c9
        cp = dhex = apr_pcalloc(p,  2 * blen + 1);
Packit 90a5c9
        if (!dhex) {
Packit 90a5c9
            rv = APR_EGENERAL;
Packit 90a5c9
        }
Packit 90a5c9
        for (i = 0; i < blen; ++i, cp += 2) {
Packit 90a5c9
            x = hex_const[buffer[i]];
Packit 90a5c9
            cp[0] = x[0];
Packit 90a5c9
            cp[1] = x[1];
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    *pdigesthex = dhex;
Packit 90a5c9
    return rv;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/**************************************************************************************************/
Packit 90a5c9
/* certificates */
Packit 90a5c9
Packit 90a5c9
struct md_cert_t {
Packit 90a5c9
    apr_pool_t *pool;
Packit 90a5c9
    X509 *x509;
Packit 90a5c9
    apr_array_header_t *alt_names;
Packit 90a5c9
};
Packit 90a5c9
Packit 90a5c9
static apr_status_t cert_cleanup(void *data)
Packit 90a5c9
{
Packit 90a5c9
    md_cert_t *cert = data;
Packit 90a5c9
    if (cert->x509) {
Packit 90a5c9
        X509_free(cert->x509);
Packit 90a5c9
        cert->x509 = NULL;
Packit 90a5c9
    }
Packit 90a5c9
    return APR_SUCCESS;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static md_cert_t *make_cert(apr_pool_t *p, X509 *x509) 
Packit 90a5c9
{
Packit 90a5c9
    md_cert_t *cert = apr_pcalloc(p, sizeof(*cert));
Packit 90a5c9
    cert->pool = p;
Packit 90a5c9
    cert->x509 = x509;
Packit 90a5c9
    apr_pool_cleanup_register(p, cert, cert_cleanup, apr_pool_cleanup_null);
Packit 90a5c9
    
Packit 90a5c9
    return cert;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
void md_cert_free(md_cert_t *cert)
Packit 90a5c9
{
Packit 90a5c9
    cert_cleanup(cert);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
void *md_cert_get_X509(struct md_cert_t *cert)
Packit 90a5c9
{
Packit 90a5c9
    return cert->x509;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
int md_cert_is_valid_now(const md_cert_t *cert)
Packit 90a5c9
{
Packit 90a5c9
    return ((X509_cmp_current_time(X509_get_notBefore(cert->x509)) < 0)
Packit 90a5c9
            && (X509_cmp_current_time(X509_get_notAfter(cert->x509)) > 0));
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
int md_cert_has_expired(const md_cert_t *cert)
Packit 90a5c9
{
Packit 90a5c9
    return (X509_cmp_current_time(X509_get_notAfter(cert->x509)) <= 0);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
apr_time_t md_cert_get_not_after(md_cert_t *cert)
Packit 90a5c9
{
Packit 90a5c9
    return md_asn1_time_get(X509_get_notAfter(cert->x509));
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
apr_time_t md_cert_get_not_before(md_cert_t *cert)
Packit 90a5c9
{
Packit 90a5c9
    return md_asn1_time_get(X509_get_notBefore(cert->x509));
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
int md_cert_covers_domain(md_cert_t *cert, const char *domain_name)
Packit 90a5c9
{
Packit 90a5c9
    if (!cert->alt_names) {
Packit 90a5c9
        md_cert_get_alt_names(&cert->alt_names, cert, cert->pool);
Packit 90a5c9
    }
Packit 90a5c9
    if (cert->alt_names) {
Packit 90a5c9
        return md_array_str_index(cert->alt_names, domain_name, 0, 0) >= 0;
Packit 90a5c9
    }
Packit 90a5c9
    return 0;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
int md_cert_covers_md(md_cert_t *cert, const md_t *md)
Packit 90a5c9
{
Packit 90a5c9
    const char *name;
Packit 90a5c9
    int i;
Packit 90a5c9
    
Packit 90a5c9
    if (!cert->alt_names) {
Packit 90a5c9
        md_cert_get_alt_names(&cert->alt_names, cert, cert->pool);
Packit 90a5c9
    }
Packit 90a5c9
    if (cert->alt_names) {
Packit 90a5c9
        md_log_perror(MD_LOG_MARK, MD_LOG_TRACE4, 0, cert->pool, "cert has %d alt names",
Packit 90a5c9
                      cert->alt_names->nelts); 
Packit 90a5c9
        for (i = 0; i < md->domains->nelts; ++i) {
Packit 90a5c9
            name = APR_ARRAY_IDX(md->domains, i, const char *);
Packit 90a5c9
            if (md_array_str_index(cert->alt_names, name, 0, 0) < 0) {
Packit 90a5c9
                md_log_perror(MD_LOG_MARK, MD_LOG_TRACE1, 0, cert->pool, 
Packit 90a5c9
                              "md domain %s not covered by cert", name);
Packit 90a5c9
                return 0;
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
        return 1;
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        md_log_perror(MD_LOG_MARK, MD_LOG_WARNING, 0, cert->pool, "cert has NO alt names");
Packit 90a5c9
    }
Packit 90a5c9
    return 0;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
apr_status_t md_cert_get_issuers_uri(const char **puri, md_cert_t *cert, apr_pool_t *p)
Packit 90a5c9
{
Packit 90a5c9
    apr_status_t rv = APR_ENOENT;
Packit 90a5c9
    STACK_OF(ACCESS_DESCRIPTION) *xinfos;
Packit 90a5c9
    const char *uri = NULL;
Packit 90a5c9
    unsigned char *buf;
Packit 90a5c9
    int i;
Packit 90a5c9
Packit 90a5c9
    xinfos = X509_get_ext_d2i(cert->x509, NID_info_access, NULL, NULL);
Packit 90a5c9
    if (xinfos) {
Packit 90a5c9
        for (i = 0; i < sk_ACCESS_DESCRIPTION_num(xinfos); i++) {
Packit 90a5c9
            ACCESS_DESCRIPTION *val = sk_ACCESS_DESCRIPTION_value(xinfos, i);
Packit 90a5c9
            if (OBJ_obj2nid(val->method) == NID_ad_ca_issuers
Packit 90a5c9
                    && val->location && val->location->type == GEN_URI) {
Packit 90a5c9
                ASN1_STRING_to_UTF8(&buf, val->location->d.uniformResourceIdentifier);
Packit 90a5c9
                uri = apr_pstrdup(p, (char *)buf);
Packit 90a5c9
                OPENSSL_free(buf);
Packit 90a5c9
                rv = APR_SUCCESS;
Packit 90a5c9
                break;
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
        sk_ACCESS_DESCRIPTION_pop_free(xinfos, ACCESS_DESCRIPTION_free);
Packit 90a5c9
    } 
Packit 90a5c9
    *puri = (APR_SUCCESS == rv)? uri : NULL;
Packit 90a5c9
    return rv;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
apr_status_t md_cert_get_alt_names(apr_array_header_t **pnames, md_cert_t *cert, apr_pool_t *p)
Packit 90a5c9
{
Packit 90a5c9
    apr_array_header_t *names;
Packit 90a5c9
    apr_status_t rv = APR_ENOENT;
Packit 90a5c9
    STACK_OF(GENERAL_NAME) *xalt_names;
Packit 90a5c9
    unsigned char *buf;
Packit 90a5c9
    int i;
Packit 90a5c9
    
Packit 90a5c9
    xalt_names = X509_get_ext_d2i(cert->x509, NID_subject_alt_name, NULL, NULL);
Packit 90a5c9
    if (xalt_names) {
Packit 90a5c9
        GENERAL_NAME *cval;
Packit 90a5c9
        
Packit 90a5c9
        names = apr_array_make(p, sk_GENERAL_NAME_num(xalt_names), sizeof(char *));
Packit 90a5c9
        for (i = 0; i < sk_GENERAL_NAME_num(xalt_names); ++i) {
Packit 90a5c9
            cval = sk_GENERAL_NAME_value(xalt_names, i);
Packit 90a5c9
            switch (cval->type) {
Packit 90a5c9
                case GEN_DNS:
Packit 90a5c9
                case GEN_URI:
Packit 90a5c9
                case GEN_IPADD:
Packit 90a5c9
                    ASN1_STRING_to_UTF8(&buf, cval->d.ia5);
Packit 90a5c9
                    APR_ARRAY_PUSH(names, const char *) = apr_pstrdup(p, (char*)buf);
Packit 90a5c9
                    OPENSSL_free(buf);
Packit 90a5c9
                    break;
Packit 90a5c9
                default:
Packit 90a5c9
                    break;
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
        sk_GENERAL_NAME_pop_free(xalt_names, GENERAL_NAME_free);
Packit 90a5c9
        rv = APR_SUCCESS;
Packit 90a5c9
    }
Packit 90a5c9
    *pnames = (APR_SUCCESS == rv)? names : NULL;
Packit 90a5c9
    return rv;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
apr_status_t md_cert_fload(md_cert_t **pcert, apr_pool_t *p, const char *fname)
Packit 90a5c9
{
Packit 90a5c9
    FILE *f;
Packit 90a5c9
    apr_status_t rv;
Packit 90a5c9
    md_cert_t *cert;
Packit 90a5c9
    X509 *x509;
Packit 90a5c9
    
Packit 90a5c9
    rv = md_util_fopen(&f, fname, "r");
Packit 90a5c9
    if (rv == APR_SUCCESS) {
Packit 90a5c9
    
Packit 90a5c9
        x509 = PEM_read_X509(f, NULL, NULL, NULL);
Packit 90a5c9
        rv = fclose(f);
Packit 90a5c9
        if (x509 != NULL) {
Packit 90a5c9
            cert =  make_cert(p, x509);
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            rv = APR_EINVAL;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    *pcert = (APR_SUCCESS == rv)? cert : NULL;
Packit 90a5c9
    return rv;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static apr_status_t cert_to_buffer(buffer_rec *buffer, md_cert_t *cert, apr_pool_t *p)
Packit 90a5c9
{
Packit 90a5c9
    BIO *bio = BIO_new(BIO_s_mem());
Packit 90a5c9
    int i;
Packit 90a5c9
    
Packit 90a5c9
    if (!bio) {
Packit 90a5c9
        return APR_ENOMEM;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    ERR_clear_error();
Packit 90a5c9
    PEM_write_bio_X509(bio, cert->x509);
Packit 90a5c9
    if (ERR_get_error() > 0) {
Packit 90a5c9
        BIO_free(bio);
Packit 90a5c9
        return APR_EINVAL;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    i = BIO_pending(bio);
Packit 90a5c9
    if (i > 0) {
Packit 90a5c9
        buffer->data = apr_palloc(p, (apr_size_t)i + 1);
Packit 90a5c9
        i = BIO_read(bio, buffer->data, i);
Packit 90a5c9
        buffer->data[i] = '\0';
Packit 90a5c9
        buffer->len = (apr_size_t)i;
Packit 90a5c9
    }
Packit 90a5c9
    BIO_free(bio);
Packit 90a5c9
    return APR_SUCCESS;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
apr_status_t md_cert_fsave(md_cert_t *cert, apr_pool_t *p, 
Packit 90a5c9
                           const char *fname, apr_fileperms_t perms)
Packit 90a5c9
{
Packit 90a5c9
    buffer_rec buffer;
Packit 90a5c9
    apr_status_t rv;
Packit 90a5c9
    
Packit 90a5c9
    if (APR_SUCCESS == (rv = cert_to_buffer(&buffer, cert, p))) {
Packit 90a5c9
        return md_util_freplace(fname, perms, p, fwrite_buffer, &buffer); 
Packit 90a5c9
    }
Packit 90a5c9
    return rv;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
apr_status_t md_cert_to_base64url(const char **ps64, md_cert_t *cert, apr_pool_t *p)
Packit 90a5c9
{
Packit 90a5c9
    buffer_rec buffer;
Packit 90a5c9
    apr_status_t rv;
Packit 90a5c9
    
Packit 90a5c9
    if (APR_SUCCESS == (rv = cert_to_buffer(&buffer, cert, p))) {
Packit 90a5c9
        *ps64 = md_util_base64url_encode(buffer.data, buffer.len, p);
Packit 90a5c9
        return APR_SUCCESS;
Packit 90a5c9
    }
Packit 90a5c9
    *ps64 = NULL;
Packit 90a5c9
    return rv;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
apr_status_t md_cert_read_http(md_cert_t **pcert, apr_pool_t *p, 
Packit 90a5c9
                               const md_http_response_t *res)
Packit 90a5c9
{
Packit 90a5c9
    const char *ct;
Packit 90a5c9
    apr_off_t data_len;
Packit 90a5c9
    apr_size_t der_len;
Packit 90a5c9
    apr_status_t rv;
Packit 90a5c9
    
Packit 90a5c9
    ct = apr_table_get(res->headers, "Content-Type");
Packit 90a5c9
    if (!res->body || !ct  || strcmp("application/pkix-cert", ct)) {
Packit 90a5c9
        return APR_ENOENT;
Packit 90a5c9
    }
Packit 90a5c9
    
Packit 90a5c9
    if (APR_SUCCESS == (rv = apr_brigade_length(res->body, 1, &data_len))) {
Packit 90a5c9
        char *der;
Packit 90a5c9
        if (data_len > 1024*1024) { /* certs usually are <2k each */
Packit 90a5c9
            return APR_EINVAL;
Packit 90a5c9
        }
Packit 90a5c9
        if (APR_SUCCESS == (rv = apr_brigade_pflatten(res->body, &der, &der_len, p))) {
Packit 90a5c9
            const unsigned char *bf = (const unsigned char*)der;
Packit 90a5c9
            X509 *x509;
Packit 90a5c9
            
Packit 90a5c9
            if (NULL == (x509 = d2i_X509(NULL, &bf, (long)der_len))) {
Packit 90a5c9
                rv = APR_EINVAL;
Packit 90a5c9
            }
Packit 90a5c9
            else {
Packit 90a5c9
                *pcert = make_cert(p, x509);
Packit 90a5c9
                rv = APR_SUCCESS;
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
        md_log_perror(MD_LOG_MARK, MD_LOG_TRACE3, rv, p, "cert parsed");
Packit 90a5c9
    }
Packit 90a5c9
    return rv;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
md_cert_state_t md_cert_state_get(md_cert_t *cert)
Packit 90a5c9
{
Packit 90a5c9
    if (cert->x509) {
Packit 90a5c9
        return md_cert_is_valid_now(cert)? MD_CERT_VALID : MD_CERT_EXPIRED;
Packit 90a5c9
    }
Packit 90a5c9
    return MD_CERT_UNKNOWN;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
apr_status_t md_chain_fappend(struct apr_array_header_t *certs, apr_pool_t *p, const char *fname)
Packit 90a5c9
{
Packit 90a5c9
    FILE *f;
Packit 90a5c9
    apr_status_t rv;
Packit 90a5c9
    X509 *x509;
Packit 90a5c9
    md_cert_t *cert;
Packit 90a5c9
    unsigned long err;
Packit 90a5c9
    
Packit 90a5c9
    rv = md_util_fopen(&f, fname, "r");
Packit 90a5c9
    if (rv == APR_SUCCESS) {
Packit 90a5c9
        ERR_clear_error();
Packit 90a5c9
        while (NULL != (x509 = PEM_read_X509(f, NULL, NULL, NULL))) {
Packit 90a5c9
            cert = make_cert(p, x509);
Packit 90a5c9
            APR_ARRAY_PUSH(certs, md_cert_t *) = cert;
Packit 90a5c9
        }
Packit 90a5c9
        fclose(f);
Packit 90a5c9
        
Packit 90a5c9
        if (0 < (err =  ERR_get_error())
Packit 90a5c9
            && !(ERR_GET_LIB(err) == ERR_LIB_PEM && ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) {
Packit 90a5c9
            /* not the expected one when no more PEM encodings are found */
Packit 90a5c9
            rv = APR_EINVAL;
Packit 90a5c9
            goto out;
Packit 90a5c9
        }
Packit 90a5c9
        
Packit 90a5c9
        if (certs->nelts == 0) {
Packit 90a5c9
            /* Did not find any. This is acceptable unless the file has a certain size
Packit 90a5c9
             * when we no longer accept it as empty chain file. Something seems to be
Packit 90a5c9
             * wrong then. */
Packit 90a5c9
            apr_finfo_t info;
Packit 90a5c9
            if (APR_SUCCESS == apr_stat(&info, fname, APR_FINFO_SIZE, p) && info.size >= 1024) {
Packit 90a5c9
                /* "Too big for a moon." */
Packit 90a5c9
                rv = APR_EINVAL;
Packit 90a5c9
                md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, 
Packit 90a5c9
                              "no certificates in non-empty chain %s", fname);
Packit 90a5c9
                goto out;
Packit 90a5c9
            }
Packit 90a5c9
        }        
Packit 90a5c9
    }
Packit 90a5c9
out:
Packit 90a5c9
    md_log_perror(MD_LOG_MARK, MD_LOG_TRACE3, rv, p, "read chain file %s, found %d certs", 
Packit 90a5c9
                  fname, certs? certs->nelts : 0);
Packit 90a5c9
    return rv;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
apr_status_t md_chain_fload(apr_array_header_t **pcerts, apr_pool_t *p, const char *fname)
Packit 90a5c9
{
Packit 90a5c9
    apr_array_header_t *certs;
Packit 90a5c9
    apr_status_t rv;
Packit 90a5c9
Packit 90a5c9
    certs = apr_array_make(p, 5, sizeof(md_cert_t *));
Packit 90a5c9
    rv = md_chain_fappend(certs, p, fname);
Packit 90a5c9
    *pcerts = (APR_SUCCESS == rv)? certs : NULL;
Packit 90a5c9
    return rv;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
apr_status_t md_chain_fsave(apr_array_header_t *certs, apr_pool_t *p, 
Packit 90a5c9
                            const char *fname, apr_fileperms_t perms)
Packit 90a5c9
{
Packit 90a5c9
    FILE *f;
Packit 90a5c9
    apr_status_t rv;
Packit 90a5c9
    const md_cert_t *cert;
Packit 90a5c9
    unsigned long err = 0;
Packit 90a5c9
    int i;
Packit 90a5c9
    
Packit 90a5c9
    (void)p;
Packit 90a5c9
    rv = md_util_fopen(&f, fname, "w");
Packit 90a5c9
    if (rv == APR_SUCCESS) {
Packit 90a5c9
        apr_file_perms_set(fname, perms);
Packit 90a5c9
        ERR_clear_error();
Packit 90a5c9
        for (i = 0; i < certs->nelts; ++i) {
Packit 90a5c9
            cert = APR_ARRAY_IDX(certs, i, const md_cert_t *);
Packit 90a5c9
            assert(cert->x509);
Packit 90a5c9
            
Packit 90a5c9
            PEM_write_X509(f, cert->x509);
Packit 90a5c9
            
Packit 90a5c9
            if (0 < (err = ERR_get_error())) {
Packit 90a5c9
                break;
Packit 90a5c9
            }
Packit 90a5c9
            
Packit 90a5c9
        }
Packit 90a5c9
        rv = fclose(f);
Packit 90a5c9
        if (err) {
Packit 90a5c9
            rv = APR_EINVAL;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    return rv;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/**************************************************************************************************/
Packit 90a5c9
/* certificate signing requests */
Packit 90a5c9
Packit 90a5c9
static const char *alt_names(apr_array_header_t *domains, apr_pool_t *p)
Packit 90a5c9
{
Packit 90a5c9
    const char *alts = "", *sep = "", *domain;
Packit 90a5c9
    int i;
Packit 90a5c9
    
Packit 90a5c9
    for (i = 0; i < domains->nelts; ++i) {
Packit 90a5c9
        domain = APR_ARRAY_IDX(domains, i, const char *);
Packit 90a5c9
        alts = apr_psprintf(p, "%s%sDNS:%s", alts, sep, domain);
Packit 90a5c9
        sep = ",";
Packit 90a5c9
    }
Packit 90a5c9
    return alts;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static apr_status_t add_ext(X509 *x, int nid, const char *value, apr_pool_t *p)
Packit 90a5c9
{
Packit 90a5c9
    X509_EXTENSION *ext = NULL;
Packit 90a5c9
    X509V3_CTX ctx;
Packit 90a5c9
    apr_status_t rv;
Packit 90a5c9
Packit 90a5c9
    X509V3_set_ctx_nodb(&ctx;;
Packit 90a5c9
    X509V3_set_ctx(&ctx, x, x, NULL, NULL, 0);
Packit 90a5c9
    if (NULL == (ext = X509V3_EXT_conf_nid(NULL, &ctx, nid, (char*)value))) {
Packit 90a5c9
        return APR_EGENERAL;
Packit 90a5c9
    }
Packit 90a5c9
    
Packit 90a5c9
    ERR_clear_error();
Packit 90a5c9
    rv = X509_add_ext(x, ext, -1)? APR_SUCCESS : APR_EINVAL;
Packit 90a5c9
    if (APR_SUCCESS != rv) {
Packit 90a5c9
        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, "add_ext nid=%dd value='%s'", 
Packit 90a5c9
                      nid, value); 
Packit 90a5c9
        
Packit 90a5c9
    }
Packit 90a5c9
    X509_EXTENSION_free(ext);
Packit 90a5c9
    return rv;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static apr_status_t sk_add_alt_names(STACK_OF(X509_EXTENSION) *exts,
Packit 90a5c9
                                     apr_array_header_t *domains, apr_pool_t *p)
Packit 90a5c9
{
Packit 90a5c9
    if (domains->nelts > 0) {
Packit 90a5c9
        X509_EXTENSION *x;
Packit 90a5c9
        
Packit 90a5c9
        x = X509V3_EXT_conf_nid(NULL, NULL, NID_subject_alt_name, (char*)alt_names(domains, p));
Packit 90a5c9
        if (NULL == x) {
Packit 90a5c9
            return APR_EGENERAL;
Packit 90a5c9
        }
Packit 90a5c9
        sk_X509_EXTENSION_push(exts, x);
Packit 90a5c9
    }
Packit 90a5c9
    return APR_SUCCESS;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
#define MD_OID_MUST_STAPLE_NUM          "1.3.6.1.5.5.7.1.24"
Packit 90a5c9
#define MD_OID_MUST_STAPLE_SNAME        "tlsfeature"
Packit 90a5c9
#define MD_OID_MUST_STAPLE_LNAME        "TLS Feature" 
Packit 90a5c9
Packit 90a5c9
static int get_must_staple_nid(void)
Packit 90a5c9
{
Packit 90a5c9
    /* Funny API, the OID for must staple might be configured or
Packit 90a5c9
     * might be not. In the second case, we need to add it. But adding
Packit 90a5c9
     * when it already is there is an error... */
Packit 90a5c9
    int nid = OBJ_txt2nid(MD_OID_MUST_STAPLE_NUM);
Packit 90a5c9
    if (NID_undef == nid) {
Packit 90a5c9
        nid = OBJ_create(MD_OID_MUST_STAPLE_NUM, 
Packit 90a5c9
                         MD_OID_MUST_STAPLE_SNAME, MD_OID_MUST_STAPLE_LNAME);
Packit 90a5c9
    }
Packit 90a5c9
    return nid;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
int md_cert_must_staple(md_cert_t *cert)
Packit 90a5c9
{
Packit 90a5c9
    /* In case we do not get the NID for it, we treat this as not set. */
Packit 90a5c9
    int nid = get_must_staple_nid();
Packit 90a5c9
    return ((NID_undef != nid)) && X509_get_ext_by_NID(cert->x509, nid, -1) >= 0;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static apr_status_t add_must_staple(STACK_OF(X509_EXTENSION) *exts, const md_t *md, apr_pool_t *p)
Packit 90a5c9
{
Packit 90a5c9
    
Packit 90a5c9
    if (md->must_staple) {
Packit 90a5c9
        X509_EXTENSION *x;
Packit 90a5c9
        int nid;
Packit 90a5c9
        
Packit 90a5c9
        nid = get_must_staple_nid();
Packit 90a5c9
        if (NID_undef == nid) {
Packit 90a5c9
            md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, 
Packit 90a5c9
                          "%s: unable to get NID for v3 must-staple TLS feature", md->name);
Packit 90a5c9
            return APR_ENOTIMPL;
Packit 90a5c9
        }
Packit 90a5c9
        x = X509V3_EXT_conf_nid(NULL, NULL, nid, (char*)"DER:30:03:02:01:05");
Packit 90a5c9
        if (NULL == x) {
Packit 90a5c9
            md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, 
Packit 90a5c9
                          "%s: unable to create x509 extension for must-staple", md->name);
Packit 90a5c9
            return APR_EGENERAL;
Packit 90a5c9
        }
Packit 90a5c9
        sk_X509_EXTENSION_push(exts, x);
Packit 90a5c9
    }
Packit 90a5c9
    return APR_SUCCESS;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
apr_status_t md_cert_req_create(const char **pcsr_der_64, const md_t *md, 
Packit 90a5c9
                                md_pkey_t *pkey, apr_pool_t *p)
Packit 90a5c9
{
Packit 90a5c9
    const char *s, *csr_der, *csr_der_64 = NULL;
Packit 90a5c9
    const unsigned char *domain;
Packit 90a5c9
    X509_REQ *csr;
Packit 90a5c9
    X509_NAME *n = NULL;
Packit 90a5c9
    STACK_OF(X509_EXTENSION) *exts = NULL;
Packit 90a5c9
    apr_status_t rv;
Packit 90a5c9
    int csr_der_len;
Packit 90a5c9
    
Packit 90a5c9
    assert(md->domains->nelts > 0);
Packit 90a5c9
    
Packit 90a5c9
    if (NULL == (csr = X509_REQ_new()) 
Packit 90a5c9
        || NULL == (exts = sk_X509_EXTENSION_new_null())
Packit 90a5c9
        || NULL == (n = X509_NAME_new())) {
Packit 90a5c9
        rv = APR_ENOMEM;
Packit 90a5c9
        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: openssl alloc X509 things", md->name);
Packit 90a5c9
        goto out; 
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* subject name == first domain */
Packit 90a5c9
    domain = APR_ARRAY_IDX(md->domains, 0, const unsigned char *);
Packit 90a5c9
    if (!X509_NAME_add_entry_by_txt(n, "CN", MBSTRING_ASC, domain, -1, -1, 0)
Packit 90a5c9
        || !X509_REQ_set_subject_name(csr, n)) {
Packit 90a5c9
        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, "%s: REQ name add entry", md->name);
Packit 90a5c9
        rv = APR_EGENERAL; goto out;
Packit 90a5c9
    }
Packit 90a5c9
    /* collect extensions, such as alt names and must staple */
Packit 90a5c9
    if (APR_SUCCESS != (rv = sk_add_alt_names(exts, md->domains, p))) {
Packit 90a5c9
        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: collecting alt names", md->name);
Packit 90a5c9
        rv = APR_EGENERAL; goto out;
Packit 90a5c9
    }
Packit 90a5c9
    if (APR_SUCCESS != (rv = add_must_staple(exts, md, p))) {
Packit 90a5c9
        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: you requested that a certificate "
Packit 90a5c9
            "is created with the 'must-staple' extension, however the SSL library was "
Packit 90a5c9
            "unable to initialized that extension. Please file a bug report on which platform "
Packit 90a5c9
            "and with which library this happens. To continue before this problem is resolved, "
Packit 90a5c9
            "configure 'MDMustStaple off' for your domains", md->name);
Packit 90a5c9
        rv = APR_EGENERAL; goto out;
Packit 90a5c9
    }
Packit 90a5c9
    /* add extensions to csr */
Packit 90a5c9
    if (sk_X509_EXTENSION_num(exts) > 0 && !X509_REQ_add_extensions(csr, exts)) {
Packit 90a5c9
        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: adding exts", md->name);
Packit 90a5c9
        rv = APR_EGENERAL; goto out;
Packit 90a5c9
    }
Packit 90a5c9
    /* add our key */
Packit 90a5c9
    if (!X509_REQ_set_pubkey(csr, pkey->pkey)) {
Packit 90a5c9
        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: set pkey in csr", md->name);
Packit 90a5c9
        rv = APR_EGENERAL; goto out;
Packit 90a5c9
    }
Packit 90a5c9
    /* sign, der encode and base64url encode */
Packit 90a5c9
    if (!X509_REQ_sign(csr, pkey->pkey, EVP_sha256())) {
Packit 90a5c9
        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: sign csr", md->name);
Packit 90a5c9
        rv = APR_EGENERAL; goto out;
Packit 90a5c9
    }
Packit 90a5c9
    if ((csr_der_len = i2d_X509_REQ(csr, NULL)) < 0) {
Packit 90a5c9
        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: der length", md->name);
Packit 90a5c9
        rv = APR_EGENERAL; goto out;
Packit 90a5c9
    }
Packit 90a5c9
    s = csr_der = apr_pcalloc(p, (apr_size_t)csr_der_len + 1);
Packit 90a5c9
    if (i2d_X509_REQ(csr, (unsigned char**)&s) != csr_der_len) {
Packit 90a5c9
        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: csr der enc", md->name);
Packit 90a5c9
        rv = APR_EGENERAL; goto out;
Packit 90a5c9
    }
Packit 90a5c9
    csr_der_64 = md_util_base64url_encode(csr_der, (apr_size_t)csr_der_len, p);
Packit 90a5c9
    rv = APR_SUCCESS;
Packit 90a5c9
    
Packit 90a5c9
out:
Packit 90a5c9
    if (exts) {
Packit 90a5c9
        sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
Packit 90a5c9
    }
Packit 90a5c9
    if (csr) {
Packit 90a5c9
        X509_REQ_free(csr);
Packit 90a5c9
    }
Packit 90a5c9
    if (n) {
Packit 90a5c9
        X509_NAME_free(n);
Packit 90a5c9
    }
Packit 90a5c9
    *pcsr_der_64 = (APR_SUCCESS == rv)? csr_der_64 : NULL;
Packit 90a5c9
    return rv;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
apr_status_t md_cert_self_sign(md_cert_t **pcert, const char *cn, 
Packit 90a5c9
                               apr_array_header_t *domains, md_pkey_t *pkey,
Packit 90a5c9
                               apr_interval_time_t valid_for, apr_pool_t *p)
Packit 90a5c9
{
Packit 90a5c9
    X509 *x;
Packit 90a5c9
    X509_NAME *n = NULL;
Packit 90a5c9
    md_cert_t *cert = NULL;
Packit 90a5c9
    apr_status_t rv;
Packit 90a5c9
    int days;
Packit 90a5c9
    BIGNUM *big_rnd = NULL;
Packit 90a5c9
    ASN1_INTEGER *asn1_rnd = NULL;
Packit 90a5c9
    unsigned char rnd[20];
Packit 90a5c9
    
Packit 90a5c9
    assert(domains);
Packit 90a5c9
    
Packit 90a5c9
    if (NULL == (x = X509_new()) 
Packit 90a5c9
        || NULL == (n = X509_NAME_new())) {
Packit 90a5c9
        rv = APR_ENOMEM;
Packit 90a5c9
        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, "%s: openssl alloc X509 things", cn);
Packit 90a5c9
        goto out; 
Packit 90a5c9
    }
Packit 90a5c9
    
Packit 90a5c9
    if (APR_SUCCESS != (rv = md_rand_bytes(rnd, sizeof(rnd), p))
Packit 90a5c9
        || !(big_rnd = BN_bin2bn(rnd, sizeof(rnd), NULL))
Packit 90a5c9
        || !(asn1_rnd = BN_to_ASN1_INTEGER(big_rnd, NULL))) {
Packit 90a5c9
        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, "%s: setup random serial", cn);
Packit 90a5c9
        rv = APR_EGENERAL; goto out;
Packit 90a5c9
    }
Packit 90a5c9
     
Packit 90a5c9
    if (1 != X509_set_version(x, 2L)) {
Packit 90a5c9
        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, "%s: setting x.509v3", cn);
Packit 90a5c9
        rv = APR_EGENERAL; goto out;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    if (!X509_set_serialNumber(x, asn1_rnd)) {
Packit 90a5c9
        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, "%s: set serial number", cn);
Packit 90a5c9
        rv = APR_EGENERAL; goto out;
Packit 90a5c9
    }
Packit 90a5c9
    /* set common name and issue */
Packit 90a5c9
    if (!X509_NAME_add_entry_by_txt(n, "CN", MBSTRING_ASC, (const unsigned char*)cn, -1, -1, 0)
Packit 90a5c9
        || !X509_set_subject_name(x, n)
Packit 90a5c9
        || !X509_set_issuer_name(x, n)) {
Packit 90a5c9
        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, "%s: name add entry", cn);
Packit 90a5c9
        rv = APR_EGENERAL; goto out;
Packit 90a5c9
    }
Packit 90a5c9
    /* cert are unconstrained (but not very trustworthy) */
Packit 90a5c9
    if (APR_SUCCESS != (rv = add_ext(x, NID_basic_constraints, "CA:FALSE, pathlen:0", p))) {
Packit 90a5c9
        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: set basic constraints ext", cn);
Packit 90a5c9
        goto out;
Packit 90a5c9
    }
Packit 90a5c9
    /* add the domain as alt name */
Packit 90a5c9
    if (APR_SUCCESS != (rv = add_ext(x, NID_subject_alt_name, alt_names(domains, p), p))) {
Packit 90a5c9
        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: set alt_name ext", cn);
Packit 90a5c9
        goto out;
Packit 90a5c9
    }
Packit 90a5c9
    /* add our key */
Packit 90a5c9
    if (!X509_set_pubkey(x, pkey->pkey)) {
Packit 90a5c9
        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: set pkey in x509", cn);
Packit 90a5c9
        rv = APR_EGENERAL; goto out;
Packit 90a5c9
    }
Packit 90a5c9
    
Packit 90a5c9
    days = (int)((apr_time_sec(valid_for) + MD_SECS_PER_DAY - 1)/ MD_SECS_PER_DAY);
Packit 90a5c9
    if (!X509_set_notBefore(x, ASN1_TIME_set(NULL, time(NULL)))) {
Packit 90a5c9
        rv = APR_EGENERAL; goto out;
Packit 90a5c9
    }
Packit 90a5c9
    if (!X509_set_notAfter(x, ASN1_TIME_adj(NULL, time(NULL), days, 0))) {
Packit 90a5c9
        rv = APR_EGENERAL; goto out;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* sign with same key */
Packit 90a5c9
    if (!X509_sign(x, pkey->pkey, EVP_sha256())) {
Packit 90a5c9
        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: sign x509", cn);
Packit 90a5c9
        rv = APR_EGENERAL; goto out;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    cert = make_cert(p, x);
Packit 90a5c9
    rv = APR_SUCCESS;
Packit 90a5c9
    
Packit 90a5c9
out:
Packit 90a5c9
    if (!cert && x) {
Packit 90a5c9
        X509_free(x);
Packit 90a5c9
    }
Packit 90a5c9
    if (n) {
Packit 90a5c9
        X509_NAME_free(n);
Packit 90a5c9
    }
Packit 90a5c9
    if (big_rnd) {
Packit 90a5c9
        BN_free(big_rnd);
Packit 90a5c9
    }
Packit 90a5c9
    if (asn1_rnd) {
Packit 90a5c9
        ASN1_INTEGER_free(asn1_rnd);
Packit 90a5c9
    }
Packit 90a5c9
    *pcert = (APR_SUCCESS == rv)? cert : NULL;
Packit 90a5c9
    return rv;
Packit 90a5c9
}
Packit 90a5c9