1 /* Copyright 2017 greenbytes GmbH (https://www.greenbytes.de)
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
21 #include <apr_buckets.h>
22 #include <apr_file_io.h>
23 #include <apr_strings.h>
25 #include <openssl/err.h>
26 #include <openssl/evp.h>
27 #include <openssl/pem.h>
28 #include <openssl/rand.h>
29 #include <openssl/rsa.h>
30 #include <openssl/x509v3.h>
40 #if APR_HAVE_SYS_TYPES_H
41 #include <sys/types.h>
47 /* getpid for Windows */
48 #if APR_HAVE_PROCESS_H
52 static int initialized;
59 #ifdef MD_HAVE_ARC4RANDOM
61 static void seed_RAND(int pid)
66 arc4random_buf(seed, sizeof(seed));
67 RAND_seed(seed, sizeof(seed));
70 #else /* ifdef MD_HAVE_ARC4RANDOM */
72 static int rand_choosenum(int l, int h)
77 apr_snprintf(buf, sizeof(buf), "%.0f",
78 (((double)(rand()%RAND_MAX)/RAND_MAX)*(h-l)));
85 static void seed_RAND(int pid)
87 unsigned char stackdata[256];
88 /* stolen from mod_ssl/ssl_engine_rand.c */
96 * seed in the current time (usually just 4 bytes)
98 my_seed.t = time(NULL);
101 * seed in the current process id (usually just 4 bytes)
105 RAND_seed((unsigned char *)&my_seed, sizeof(my_seed));
108 * seed in some current state of the run-time stack (128 bytes)
110 n = rand_choosenum(0, sizeof(stackdata)-128-1);
111 RAND_seed(stackdata+n, 128);
114 #endif /*ifdef MD_HAVE_ARC4RANDOM (else part) */
117 apr_status_t md_crypt_init(apr_pool_t *pool)
124 ERR_load_crypto_strings();
125 OpenSSL_add_all_algorithms();
127 md_log_perror(MD_LOG_MARK, MD_LOG_TRACE2, 0, pool, "initializing RAND");
128 while (!RAND_status()) {
142 static apr_status_t fwrite_buffer(void *baton, apr_file_t *f, apr_pool_t *p)
144 buffer_rec *buf = baton;
147 return apr_file_write_full(f, buf->data, buf->len, &buf->len);
150 apr_status_t md_rand_bytes(unsigned char *buf, apr_size_t len, apr_pool_t *p)
157 if (APR_SUCCESS == (rv = md_crypt_init(p))) {
158 RAND_bytes((unsigned char*)buf, (int)len);
164 const char *pass_phrase;
168 static int pem_passwd(char *buf, int size, int rwflag, void *baton)
170 passwd_ctx *ctx = baton;
173 if (ctx->pass_len > 0) {
174 if (ctx->pass_len < size) {
175 size = (int)ctx->pass_len;
177 memcpy(buf, ctx->pass_phrase, (size_t)size);
179 return ctx->pass_len;
182 /**************************************************************************************************/
183 /* date time things */
185 /* Get the apr time (micro seconds, since 1970) from an ASN1 time, as stored in X509
186 * certificates. OpenSSL now has a utility function, but other *SSL derivatives have
187 * not caughts up yet or chose to ignore. An alternative is implemented, we prefer
188 * however the *SSL to maintain such things.
190 static apr_time_t md_asn1_time_get(const ASN1_TIME* time)
192 #ifdef LIBRESSL_VERSION_NUMBER
193 /* courtesy: https://stackoverflow.com/questions/10975542/asn1-time-to-time-t-conversion#11263731
194 * all bugs are mine */
197 const char* str = (const char*) time->data;
200 memset(&t, 0, sizeof(t));
202 if (time->type == V_ASN1_UTCTIME) {/* two digit year */
203 t.tm_year = (str[i++] - '0') * 10;
204 t.tm_year += (str[i++] - '0');
208 else if (time->type == V_ASN1_GENERALIZEDTIME) {/* four digit year */
209 t.tm_year = (str[i++] - '0') * 1000;
210 t.tm_year+= (str[i++] - '0') * 100;
211 t.tm_year+= (str[i++] - '0') * 10;
212 t.tm_year+= (str[i++] - '0');
215 t.tm_mon = (str[i++] - '0') * 10;
216 t.tm_mon += (str[i++] - '0') - 1; /* -1 since January is 0 not 1. */
217 t.tm_mday = (str[i++] - '0') * 10;
218 t.tm_mday+= (str[i++] - '0');
219 t.tm_hour = (str[i++] - '0') * 10;
220 t.tm_hour+= (str[i++] - '0');
221 t.tm_min = (str[i++] - '0') * 10;
222 t.tm_min += (str[i++] - '0');
223 t.tm_sec = (str[i++] - '0') * 10;
224 t.tm_sec += (str[i++] - '0');
226 if (APR_SUCCESS == apr_time_exp_gmt_get(&ts, &t)) {
232 apr_time_t ts = apr_time_now();
234 if (ASN1_TIME_diff(&days, &secs, NULL, time)) {
235 ts += apr_time_from_sec((days * MD_SECS_PER_DAY) + secs);
242 /**************************************************************************************************/
245 md_json_t *md_pkey_spec_to_json(const md_pkey_spec_t *spec, apr_pool_t *p)
247 md_json_t *json = md_json_create(p);
249 switch (spec->type) {
250 case MD_PKEY_TYPE_DEFAULT:
251 md_json_sets("Default", json, MD_KEY_TYPE, NULL);
253 case MD_PKEY_TYPE_RSA:
254 md_json_sets("RSA", json, MD_KEY_TYPE, NULL);
255 if (spec->params.rsa.bits >= MD_PKEY_RSA_BITS_MIN) {
256 md_json_setl((long)spec->params.rsa.bits, json, MD_KEY_BITS, NULL);
260 md_json_sets("Unsupported", json, MD_KEY_TYPE, NULL);
267 md_pkey_spec_t *md_pkey_spec_from_json(struct md_json_t *json, apr_pool_t *p)
269 md_pkey_spec_t *spec = apr_pcalloc(p, sizeof(*spec));
274 s = md_json_gets(json, MD_KEY_TYPE, NULL);
275 if (!s || !apr_strnatcasecmp("Default", s)) {
276 spec->type = MD_PKEY_TYPE_DEFAULT;
278 else if (!apr_strnatcasecmp("RSA", s)) {
279 spec->type = MD_PKEY_TYPE_RSA;
280 l = md_json_getl(json, MD_KEY_BITS, NULL);
281 if (l >= MD_PKEY_RSA_BITS_MIN) {
282 spec->params.rsa.bits = (unsigned int)l;
285 spec->params.rsa.bits = MD_PKEY_RSA_BITS_DEF;
292 int md_pkey_spec_eq(md_pkey_spec_t *spec1, md_pkey_spec_t *spec2)
294 if (spec1 == spec2) {
297 if (spec1 && spec2 && spec1->type == spec2->type) {
298 switch (spec1->type) {
299 case MD_PKEY_TYPE_DEFAULT:
301 case MD_PKEY_TYPE_RSA:
302 if (spec1->params.rsa.bits == spec2->params.rsa.bits) {
311 static md_pkey_t *make_pkey(apr_pool_t *p)
313 md_pkey_t *pkey = apr_pcalloc(p, sizeof(*pkey));
318 static apr_status_t pkey_cleanup(void *data)
320 md_pkey_t *pkey = data;
322 EVP_PKEY_free(pkey->pkey);
328 void md_pkey_free(md_pkey_t *pkey)
333 void *md_pkey_get_EVP_PKEY(struct md_pkey_t *pkey)
338 apr_status_t md_pkey_fload(md_pkey_t **ppkey, apr_pool_t *p,
339 const char *key, apr_size_t key_len,
342 apr_status_t rv = APR_ENOENT;
348 if (NULL != (bf = BIO_new_file(fname, "r"))) {
349 ctx.pass_phrase = key;
350 ctx.pass_len = (int)key_len;
353 pkey->pkey = PEM_read_bio_PrivateKey(bf, NULL, pem_passwd, &ctx);
356 if (pkey->pkey != NULL) {
358 apr_pool_cleanup_register(p, pkey, pkey_cleanup, apr_pool_cleanup_null);
361 unsigned long err = ERR_get_error();
363 md_log_perror(MD_LOG_MARK, MD_LOG_WARNING, rv, p,
364 "error loading pkey %s: %s (pass phrase was %snull)", fname,
365 ERR_error_string(err, NULL), key? "not " : "");
368 *ppkey = (APR_SUCCESS == rv)? pkey : NULL;
372 static apr_status_t pkey_to_buffer(buffer_rec *buffer, md_pkey_t *pkey, apr_pool_t *p,
373 const char *pass, apr_size_t pass_len)
375 BIO *bio = BIO_new(BIO_s_mem());
376 const EVP_CIPHER *cipher = NULL;
377 pem_password_cb *cb = NULL;
378 void *cb_baton = NULL;
386 if (pass_len > INT_MAX) {
389 if (pass && pass_len > 0) {
390 ctx.pass_phrase = pass;
391 ctx.pass_len = (int)pass_len;
394 cipher = EVP_aes_256_cbc();
401 if (!PEM_write_bio_PrivateKey(bio, pkey->pkey, cipher, NULL, 0, cb, cb_baton)) {
403 err = ERR_get_error();
404 md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, "PEM_write key: %ld %s",
405 err, ERR_error_string(err, NULL));
409 i = BIO_pending(bio);
411 buffer->data = apr_palloc(p, (apr_size_t)i + 1);
412 i = BIO_read(bio, buffer->data, i);
413 buffer->data[i] = '\0';
414 buffer->len = (apr_size_t)i;
420 apr_status_t md_pkey_fsave(md_pkey_t *pkey, apr_pool_t *p,
421 const char *pass_phrase, apr_size_t pass_len,
422 const char *fname, apr_fileperms_t perms)
427 if (APR_SUCCESS == (rv = pkey_to_buffer(&buffer, pkey, p, pass_phrase, pass_len))) {
428 return md_util_freplace(fname, perms, p, fwrite_buffer, &buffer);
430 md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, p, "save pkey %s (%s pass phrase, len=%d)",
431 fname, pass_len > 0? "with" : "without", (int)pass_len);
435 static apr_status_t gen_rsa(md_pkey_t **ppkey, apr_pool_t *p, unsigned int bits)
437 EVP_PKEY_CTX *ctx = NULL;
440 *ppkey = make_pkey(p);
441 ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
443 && EVP_PKEY_keygen_init(ctx) >= 0
444 && EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, (int)bits) >= 0
445 && EVP_PKEY_keygen(ctx, &(*ppkey)->pkey) >= 0) {
449 md_log_perror(MD_LOG_MARK, MD_LOG_WARNING, 0, p, "error generate pkey RSA %d", bits);
455 EVP_PKEY_CTX_free(ctx);
460 apr_status_t md_pkey_gen(md_pkey_t **ppkey, apr_pool_t *p, md_pkey_spec_t *spec)
462 md_pkey_type_t ptype = spec? spec->type : MD_PKEY_TYPE_DEFAULT;
464 case MD_PKEY_TYPE_DEFAULT:
465 return gen_rsa(ppkey, p, MD_PKEY_RSA_BITS_DEF);
466 case MD_PKEY_TYPE_RSA:
467 return gen_rsa(ppkey, p, spec->params.rsa.bits);
473 #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
475 #ifndef NID_tlsfeature
476 #define NID_tlsfeature 1020
479 static void RSA_get0_key(const RSA *r,
480 const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
492 static const char *bn64(const BIGNUM *b, apr_pool_t *p)
495 apr_size_t len = (apr_size_t)BN_num_bytes(b);
496 char *buffer = apr_pcalloc(p, len);
498 BN_bn2bin(b, (unsigned char *)buffer);
499 return md_util_base64url_encode(buffer, len, p);
505 const char *md_pkey_get_rsa_e64(md_pkey_t *pkey, apr_pool_t *p)
508 RSA *rsa = EVP_PKEY_get1_RSA(pkey->pkey);
513 RSA_get0_key(rsa, NULL, &e, NULL);
517 const char *md_pkey_get_rsa_n64(md_pkey_t *pkey, apr_pool_t *p)
520 RSA *rsa = EVP_PKEY_get1_RSA(pkey->pkey);
525 RSA_get0_key(rsa, &n, NULL, NULL);
529 apr_status_t md_crypt_sign64(const char **psign64, md_pkey_t *pkey, apr_pool_t *p,
530 const char *d, size_t dlen)
532 EVP_MD_CTX *ctx = NULL;
535 const char *sign64 = NULL;
536 apr_status_t rv = APR_ENOMEM;
538 buffer = apr_pcalloc(p, (apr_size_t)EVP_PKEY_size(pkey->pkey));
540 ctx = EVP_MD_CTX_create();
543 if (EVP_SignInit_ex(ctx, EVP_sha256(), NULL)) {
545 if (EVP_SignUpdate(ctx, d, dlen)) {
546 if (EVP_SignFinal(ctx, (unsigned char*)buffer, &blen, pkey->pkey)) {
547 sign64 = md_util_base64url_encode(buffer, blen, p);
557 EVP_MD_CTX_destroy(ctx);
561 if (rv != APR_SUCCESS) {
562 md_log_perror(MD_LOG_MARK, MD_LOG_WARNING, rv, p, "signing");
569 static apr_status_t sha256_digest(unsigned char **pdigest, size_t *pdigest_len,
570 apr_pool_t *p, const char *d, size_t dlen)
572 EVP_MD_CTX *ctx = NULL;
573 unsigned char *buffer;
574 apr_status_t rv = APR_ENOMEM;
577 buffer = apr_pcalloc(p, EVP_MAX_MD_SIZE);
579 ctx = EVP_MD_CTX_create();
582 if (EVP_DigestInit_ex(ctx, EVP_sha256(), NULL)) {
584 if (EVP_DigestUpdate(ctx, d, dlen)) {
585 if (EVP_DigestFinal(ctx, buffer, &blen)) {
593 EVP_MD_CTX_destroy(ctx);
597 if (APR_SUCCESS == rv) {
602 md_log_perror(MD_LOG_MARK, MD_LOG_WARNING, rv, p, "digest");
609 apr_status_t md_crypt_sha256_digest64(const char **pdigest64, apr_pool_t *p,
610 const char *d, size_t dlen)
612 const char *digest64 = NULL;
613 unsigned char *buffer;
617 if (APR_SUCCESS == (rv = sha256_digest(&buffer, &blen, p, d, dlen))) {
618 if (NULL == (digest64 = md_util_base64url_encode((const char*)buffer, blen, p))) {
622 *pdigest64 = digest64;
626 static const char * const hex_const[] = {
627 "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0a", "0b", "0c", "0d", "0e", "0f",
628 "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1a", "1b", "1c", "1d", "1e", "1f",
629 "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2a", "2b", "2c", "2d", "2e", "2f",
630 "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3a", "3b", "3c", "3d", "3e", "3f",
631 "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4a", "4b", "4c", "4d", "4e", "4f",
632 "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5a", "5b", "5c", "5d", "5e", "5f",
633 "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6a", "6b", "6c", "6d", "6e", "6f",
634 "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7a", "7b", "7c", "7d", "7e", "7f",
635 "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8a", "8b", "8c", "8d", "8e", "8f",
636 "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9a", "9b", "9c", "9d", "9e", "9f",
637 "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "aa", "ab", "ac", "ad", "ae", "af",
638 "b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7", "b8", "b9", "ba", "bb", "bc", "bd", "be", "bf",
639 "c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "ca", "cb", "cc", "cd", "ce", "cf",
640 "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "da", "db", "dc", "dd", "de", "df",
641 "e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7", "e8", "e9", "ea", "eb", "ec", "ed", "ee", "ef",
642 "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "fa", "fb", "fc", "fd", "fe", "ff",
645 apr_status_t md_crypt_sha256_digest_hex(const char **pdigesthex, apr_pool_t *p,
646 const char *d, size_t dlen)
648 char *dhex = NULL, *cp;
650 unsigned char *buffer;
655 if (APR_SUCCESS == (rv = sha256_digest(&buffer, &blen, p, d, dlen))) {
656 cp = dhex = apr_pcalloc(p, 2 * blen + 1);
660 for (i = 0; i < blen; ++i, cp += 2) {
661 x = hex_const[buffer[i]];
670 /**************************************************************************************************/
676 apr_array_header_t *alt_names;
679 static apr_status_t cert_cleanup(void *data)
681 md_cert_t *cert = data;
683 X509_free(cert->x509);
689 static md_cert_t *make_cert(apr_pool_t *p, X509 *x509)
691 md_cert_t *cert = apr_pcalloc(p, sizeof(*cert));
694 apr_pool_cleanup_register(p, cert, cert_cleanup, apr_pool_cleanup_null);
699 void md_cert_free(md_cert_t *cert)
704 void *md_cert_get_X509(struct md_cert_t *cert)
709 int md_cert_is_valid_now(const md_cert_t *cert)
711 return ((X509_cmp_current_time(X509_get_notBefore(cert->x509)) < 0)
712 && (X509_cmp_current_time(X509_get_notAfter(cert->x509)) > 0));
715 int md_cert_has_expired(const md_cert_t *cert)
717 return (X509_cmp_current_time(X509_get_notAfter(cert->x509)) <= 0);
720 apr_time_t md_cert_get_not_after(md_cert_t *cert)
722 return md_asn1_time_get(X509_get_notAfter(cert->x509));
725 apr_time_t md_cert_get_not_before(md_cert_t *cert)
727 return md_asn1_time_get(X509_get_notBefore(cert->x509));
730 int md_cert_covers_domain(md_cert_t *cert, const char *domain_name)
732 if (!cert->alt_names) {
733 md_cert_get_alt_names(&cert->alt_names, cert, cert->pool);
735 if (cert->alt_names) {
736 return md_array_str_index(cert->alt_names, domain_name, 0, 0) >= 0;
741 int md_cert_covers_md(md_cert_t *cert, const md_t *md)
746 if (!cert->alt_names) {
747 md_cert_get_alt_names(&cert->alt_names, cert, cert->pool);
749 if (cert->alt_names) {
750 md_log_perror(MD_LOG_MARK, MD_LOG_TRACE4, 0, cert->pool, "cert has %d alt names",
751 cert->alt_names->nelts);
752 for (i = 0; i < md->domains->nelts; ++i) {
753 name = APR_ARRAY_IDX(md->domains, i, const char *);
754 if (md_array_str_index(cert->alt_names, name, 0, 0) < 0) {
755 md_log_perror(MD_LOG_MARK, MD_LOG_TRACE1, 0, cert->pool,
756 "md domain %s not covered by cert", name);
763 md_log_perror(MD_LOG_MARK, MD_LOG_WARNING, 0, cert->pool, "cert has NO alt names");
768 apr_status_t md_cert_get_issuers_uri(const char **puri, md_cert_t *cert, apr_pool_t *p)
770 int i, ext_idx, nid = NID_info_access;
772 X509V3_EXT_METHOD *ext_cls;
774 const char *uri = NULL;
775 apr_status_t rv = APR_ENOENT;
777 /* Waddle through x509 API history to get someone that may be able
778 * to hand us the issuer url for the cert chain */
779 ext_idx = X509_get_ext_by_NID(cert->x509, nid, -1);
780 ext = (ext_idx >= 0)? X509_get_ext(cert->x509, ext_idx) : NULL;
781 ext_cls = ext? (X509V3_EXT_METHOD*)X509V3_EXT_get(ext) : NULL;
782 if (ext_cls && (ext_data = X509_get_ext_d2i(cert->x509, nid, 0, 0))) {
784 STACK_OF(CONF_VALUE) *ext_vals = ext_cls->i2v(ext_cls, ext_data, 0);
786 for (i = 0; i < sk_CONF_VALUE_num(ext_vals); ++i) {
787 cval = sk_CONF_VALUE_value(ext_vals, i);
788 if (!strcmp("CA Issuers - URI", cval->name)) {
789 uri = apr_pstrdup(p, cval->value);
795 *puri = (APR_SUCCESS == rv)? uri : NULL;
799 apr_status_t md_cert_get_alt_names(apr_array_header_t **pnames, md_cert_t *cert, apr_pool_t *p)
801 apr_array_header_t *names;
802 apr_status_t rv = APR_ENOENT;
803 STACK_OF(GENERAL_NAME) *xalt_names;
807 xalt_names = (GENERAL_NAMES*)X509_get_ext_d2i(cert->x509, NID_subject_alt_name, NULL, NULL);
811 names = apr_array_make(p, sk_GENERAL_NAME_num(xalt_names), sizeof(char *));
812 for (i = 0; i < sk_GENERAL_NAME_num(xalt_names); ++i) {
813 cval = sk_GENERAL_NAME_value(xalt_names, i);
814 switch (cval->type) {
818 ASN1_STRING_to_UTF8(&buf, cval->d.ia5);
819 APR_ARRAY_PUSH(names, const char *) = apr_pstrdup(p, (char*)buf);
828 *pnames = (APR_SUCCESS == rv)? names : NULL;
832 apr_status_t md_cert_fload(md_cert_t **pcert, apr_pool_t *p, const char *fname)
839 rv = md_util_fopen(&f, fname, "r");
840 if (rv == APR_SUCCESS) {
842 x509 = PEM_read_X509(f, NULL, NULL, NULL);
845 cert = make_cert(p, x509);
852 *pcert = (APR_SUCCESS == rv)? cert : NULL;
856 static apr_status_t cert_to_buffer(buffer_rec *buffer, md_cert_t *cert, apr_pool_t *p)
858 BIO *bio = BIO_new(BIO_s_mem());
866 PEM_write_bio_X509(bio, cert->x509);
867 if (ERR_get_error() > 0) {
872 i = BIO_pending(bio);
874 buffer->data = apr_palloc(p, (apr_size_t)i + 1);
875 i = BIO_read(bio, buffer->data, i);
876 buffer->data[i] = '\0';
877 buffer->len = (apr_size_t)i;
883 apr_status_t md_cert_fsave(md_cert_t *cert, apr_pool_t *p,
884 const char *fname, apr_fileperms_t perms)
889 if (APR_SUCCESS == (rv = cert_to_buffer(&buffer, cert, p))) {
890 return md_util_freplace(fname, perms, p, fwrite_buffer, &buffer);
895 apr_status_t md_cert_to_base64url(const char **ps64, md_cert_t *cert, apr_pool_t *p)
900 if (APR_SUCCESS == (rv = cert_to_buffer(&buffer, cert, p))) {
901 *ps64 = md_util_base64url_encode(buffer.data, buffer.len, p);
908 apr_status_t md_cert_read_http(md_cert_t **pcert, apr_pool_t *p,
909 const md_http_response_t *res)
916 ct = apr_table_get(res->headers, "Content-Type");
917 if (!res->body || !ct || strcmp("application/pkix-cert", ct)) {
921 if (APR_SUCCESS == (rv = apr_brigade_length(res->body, 1, &data_len))) {
923 if (data_len > 1024*1024) { /* certs usually are <2k each */
926 if (APR_SUCCESS == (rv = apr_brigade_pflatten(res->body, &der, &der_len, p))) {
927 const unsigned char *bf = (const unsigned char*)der;
930 if (NULL == (x509 = d2i_X509(NULL, &bf, (long)der_len))) {
934 *pcert = make_cert(p, x509);
938 md_log_perror(MD_LOG_MARK, MD_LOG_TRACE3, rv, p, "cert parsed");
943 md_cert_state_t md_cert_state_get(md_cert_t *cert)
946 return md_cert_is_valid_now(cert)? MD_CERT_VALID : MD_CERT_EXPIRED;
948 return MD_CERT_UNKNOWN;
951 apr_status_t md_chain_fappend(struct apr_array_header_t *certs, apr_pool_t *p, const char *fname)
959 rv = md_util_fopen(&f, fname, "r");
960 if (rv == APR_SUCCESS) {
962 while (NULL != (x509 = PEM_read_X509(f, NULL, NULL, NULL))) {
963 cert = make_cert(p, x509);
964 APR_ARRAY_PUSH(certs, md_cert_t *) = cert;
968 if (0 < (err = ERR_get_error())
969 && !(ERR_GET_LIB(err) == ERR_LIB_PEM && ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) {
970 /* not the expected one when no more PEM encodings are found */
975 if (certs->nelts == 0) {
976 /* Did not find any. This is acceptable unless the file has a certain size
977 * when we no longer accept it as empty chain file. Something seems to be
980 if (APR_SUCCESS == apr_stat(&info, fname, APR_FINFO_SIZE, p) && info.size >= 1024) {
981 /* "Too big for a moon." */
983 md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p,
984 "no certificates in non-empty chain %s", fname);
990 md_log_perror(MD_LOG_MARK, MD_LOG_TRACE3, rv, p, "read chain file %s, found %d certs",
991 fname, certs? certs->nelts : 0);
995 apr_status_t md_chain_fload(apr_array_header_t **pcerts, apr_pool_t *p, const char *fname)
997 apr_array_header_t *certs;
1000 certs = apr_array_make(p, 5, sizeof(md_cert_t *));
1001 rv = md_chain_fappend(certs, p, fname);
1002 *pcerts = (APR_SUCCESS == rv)? certs : NULL;
1006 apr_status_t md_chain_fsave(apr_array_header_t *certs, apr_pool_t *p,
1007 const char *fname, apr_fileperms_t perms)
1011 const md_cert_t *cert;
1012 unsigned long err = 0;
1016 rv = md_util_fopen(&f, fname, "w");
1017 if (rv == APR_SUCCESS) {
1018 apr_file_perms_set(fname, perms);
1020 for (i = 0; i < certs->nelts; ++i) {
1021 cert = APR_ARRAY_IDX(certs, i, const md_cert_t *);
1024 PEM_write_X509(f, cert->x509);
1026 if (0 < (err = ERR_get_error())) {
1039 /**************************************************************************************************/
1040 /* certificate signing requests */
1042 static const char *alt_names(apr_array_header_t *domains, apr_pool_t *p)
1044 const char *alts = "", *sep = "", *domain;
1047 for (i = 0; i < domains->nelts; ++i) {
1048 domain = APR_ARRAY_IDX(domains, i, const char *);
1049 alts = apr_psprintf(p, "%s%sDNS:%s", alts, sep, domain);
1055 static apr_status_t add_ext(X509 *x, int nid, const char *value, apr_pool_t *p)
1057 X509_EXTENSION *ext = NULL;
1061 X509V3_set_ctx_nodb(&ctx);
1062 X509V3_set_ctx(&ctx, x, x, NULL, NULL, 0);
1063 if (NULL == (ext = X509V3_EXT_conf_nid(NULL, &ctx, nid, (char*)value))) {
1064 return APR_EGENERAL;
1068 rv = X509_add_ext(x, ext, -1)? APR_SUCCESS : APR_EINVAL;
1069 if (APR_SUCCESS != rv) {
1070 md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, "add_ext nid=%dd value='%s'",
1074 X509_EXTENSION_free(ext);
1078 static apr_status_t sk_add_alt_names(STACK_OF(X509_EXTENSION) *exts,
1079 apr_array_header_t *domains, apr_pool_t *p)
1081 if (domains->nelts > 0) {
1084 x = X509V3_EXT_conf_nid(NULL, NULL, NID_subject_alt_name, (char*)alt_names(domains, p));
1086 return APR_EGENERAL;
1088 sk_X509_EXTENSION_push(exts, x);
1093 static apr_status_t add_must_staple(STACK_OF(X509_EXTENSION) *exts, const md_t *md, apr_pool_t *p)
1096 if (md->must_staple) {
1100 nid = OBJ_create("1.3.6.1.5.5.7.1.24", "OCSPReq", "OCSP Request");
1101 if (NID_undef == nid) {
1102 md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p,
1103 "%s: unable to get NID for must-staple", md->name);
1104 return APR_EGENERAL;
1106 x = X509V3_EXT_conf_nid(NULL, NULL, nid, (char*)"DER:30:03:02:01:05");
1108 md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p,
1109 "%s: unable to get x509 extension for must-staple", md->name);
1110 return APR_EGENERAL;
1112 sk_X509_EXTENSION_push(exts, x);
1117 apr_status_t md_cert_req_create(const char **pcsr_der_64, const md_t *md,
1118 md_pkey_t *pkey, apr_pool_t *p)
1120 const char *s, *csr_der, *csr_der_64 = NULL;
1121 const unsigned char *domain;
1123 X509_NAME *n = NULL;
1124 STACK_OF(X509_EXTENSION) *exts = NULL;
1128 assert(md->domains->nelts > 0);
1130 if (NULL == (csr = X509_REQ_new())
1131 || NULL == (exts = sk_X509_EXTENSION_new_null())
1132 || NULL == (n = X509_NAME_new())) {
1134 md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: openssl alloc X509 things", md->name);
1138 /* subject name == first domain */
1139 domain = APR_ARRAY_IDX(md->domains, 0, const unsigned char *);
1140 if (!X509_NAME_add_entry_by_txt(n, "CN", MBSTRING_ASC, domain, -1, -1, 0)
1141 || !X509_REQ_set_subject_name(csr, n)) {
1142 md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, "%s: REQ name add entry", md->name);
1143 rv = APR_EGENERAL; goto out;
1145 /* collect extensions, such as alt names and must staple */
1146 if (APR_SUCCESS != (rv = sk_add_alt_names(exts, md->domains, p))) {
1147 md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: collecting alt names", md->name);
1148 rv = APR_EGENERAL; goto out;
1150 if (APR_SUCCESS != (rv = add_must_staple(exts, md, p))) {
1151 md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: must staple", md->name);
1152 rv = APR_EGENERAL; goto out;
1154 /* add extensions to csr */
1155 if (sk_X509_EXTENSION_num(exts) > 0 && !X509_REQ_add_extensions(csr, exts)) {
1156 md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: adding exts", md->name);
1157 rv = APR_EGENERAL; goto out;
1160 if (!X509_REQ_set_pubkey(csr, pkey->pkey)) {
1161 md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: set pkey in csr", md->name);
1162 rv = APR_EGENERAL; goto out;
1164 /* sign, der encode and base64url encode */
1165 if (!X509_REQ_sign(csr, pkey->pkey, EVP_sha256())) {
1166 md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: sign csr", md->name);
1167 rv = APR_EGENERAL; goto out;
1169 if ((csr_der_len = i2d_X509_REQ(csr, NULL)) < 0) {
1170 md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: der length", md->name);
1171 rv = APR_EGENERAL; goto out;
1173 s = csr_der = apr_pcalloc(p, (apr_size_t)csr_der_len + 1);
1174 if (i2d_X509_REQ(csr, (unsigned char**)&s) != csr_der_len) {
1175 md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: csr der enc", md->name);
1176 rv = APR_EGENERAL; goto out;
1178 csr_der_64 = md_util_base64url_encode(csr_der, (apr_size_t)csr_der_len, p);
1183 sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
1191 *pcsr_der_64 = (APR_SUCCESS == rv)? csr_der_64 : NULL;
1195 apr_status_t md_cert_self_sign(md_cert_t **pcert, const char *cn,
1196 apr_array_header_t *domains, md_pkey_t *pkey,
1197 apr_interval_time_t valid_for, apr_pool_t *p)
1200 X509_NAME *n = NULL;
1201 md_cert_t *cert = NULL;
1204 BIGNUM *big_rnd = NULL;
1205 ASN1_INTEGER *asn1_rnd = NULL;
1206 unsigned char rnd[20];
1210 if (NULL == (x = X509_new())
1211 || NULL == (n = X509_NAME_new())) {
1213 md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, "%s: openssl alloc X509 things", cn);
1217 if (APR_SUCCESS != (rv = md_rand_bytes(rnd, sizeof(rnd), p))
1218 || !(big_rnd = BN_bin2bn(rnd, sizeof(rnd), NULL))
1219 || !(asn1_rnd = BN_to_ASN1_INTEGER(big_rnd, NULL))) {
1220 md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, "%s: setup random serial", cn);
1221 rv = APR_EGENERAL; goto out;
1224 if (1 != X509_set_version(x, 2L)) {
1225 md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, "%s: setting x.509v3", cn);
1226 rv = APR_EGENERAL; goto out;
1229 if (!X509_set_serialNumber(x, asn1_rnd)) {
1230 md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, "%s: set serial number", cn);
1231 rv = APR_EGENERAL; goto out;
1233 /* set common name and issue */
1234 if (!X509_NAME_add_entry_by_txt(n, "CN", MBSTRING_ASC, (const unsigned char*)cn, -1, -1, 0)
1235 || !X509_set_subject_name(x, n)
1236 || !X509_set_issuer_name(x, n)) {
1237 md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, "%s: name add entry", cn);
1238 rv = APR_EGENERAL; goto out;
1240 /* cert are uncontrained (but not very trustworthy) */
1241 if (APR_SUCCESS != (rv = add_ext(x, NID_basic_constraints, "CA:FALSE, pathlen:0", p))) {
1242 md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: set basic constraints ext", cn);
1245 /* add the domain as alt name */
1246 if (APR_SUCCESS != (rv = add_ext(x, NID_subject_alt_name, alt_names(domains, p), p))) {
1247 md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: set alt_name ext", cn);
1251 if (!X509_set_pubkey(x, pkey->pkey)) {
1252 md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: set pkey in x509", cn);
1253 rv = APR_EGENERAL; goto out;
1256 days = (int)((apr_time_sec(valid_for) + MD_SECS_PER_DAY - 1)/ MD_SECS_PER_DAY);
1257 if (!X509_set_notBefore(x, ASN1_TIME_set(NULL, time(NULL)))) {
1258 rv = APR_EGENERAL; goto out;
1260 if (!X509_set_notAfter(x, ASN1_TIME_adj(NULL, time(NULL), days, 0))) {
1261 rv = APR_EGENERAL; goto out;
1264 /* sign with same key */
1265 if (!X509_sign(x, pkey->pkey, EVP_sha256())) {
1266 md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: sign x509", cn);
1267 rv = APR_EGENERAL; goto out;
1270 cert = make_cert(p, x);
1284 ASN1_INTEGER_free(asn1_rnd);
1286 *pcert = (APR_SUCCESS == rv)? cert : NULL;