1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements.  See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License.  You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*                      _             _
18 *  _ __ ___   ___   __| |    ___ ___| |  mod_ssl
19 * | '_ ` _ \ / _ \ / _` |   / __/ __| |  Apache Interface to OpenSSL
20 * | | | | | | (_) | (_| |   \__ \__ \ |
21 * |_| |_| |_|\___/ \__,_|___|___/___/_|
22 *                      |_____|
23 *  ssl_util_ssl.c
24 *  Additional Utility Functions for OpenSSL
25 */
26
27#include "ssl_private.h"
28
29/*  _________________________________________________________________
30**
31**  Additional High-Level Functions for OpenSSL
32**  _________________________________________________________________
33*/
34
35/* we initialize this index at startup time
36 * and never write to it at request time,
37 * so this static is thread safe.
38 * also note that OpenSSL increments at static variable when
39 * SSL_get_ex_new_index() is called, so we _must_ do this at startup.
40 */
41static int SSL_app_data2_idx = -1;
42
43void SSL_init_app_data2_idx(void)
44{
45    int i;
46
47    if (SSL_app_data2_idx > -1) {
48        return;
49    }
50
51    /* we _do_ need to call this twice */
52    for (i=0; i<=1; i++) {
53        SSL_app_data2_idx =
54            SSL_get_ex_new_index(0,
55                                 "Second Application Data for SSL",
56                                 NULL, NULL, NULL);
57    }
58}
59
60void *SSL_get_app_data2(SSL *ssl)
61{
62    return (void *)SSL_get_ex_data(ssl, SSL_app_data2_idx);
63}
64
65void SSL_set_app_data2(SSL *ssl, void *arg)
66{
67    SSL_set_ex_data(ssl, SSL_app_data2_idx, (char *)arg);
68    return;
69}
70
71/*  _________________________________________________________________
72**
73**  High-Level Certificate / Private Key Loading
74**  _________________________________________________________________
75*/
76
77X509 *SSL_read_X509(char* filename, X509 **x509, modssl_read_bio_cb_fn *cb)
78{
79    X509 *rc;
80    BIO *bioS;
81    BIO *bioF;
82
83    /* 1. try PEM (= DER+Base64+headers) */
84    if ((bioS=BIO_new_file(filename, "r")) == NULL)
85        return NULL;
86    rc = modssl_PEM_read_bio_X509 (bioS, x509, cb, NULL);
87    BIO_free(bioS);
88
89    if (rc == NULL) {
90        /* 2. try DER+Base64 */
91        if ((bioS=BIO_new_file(filename, "r")) == NULL)
92            return NULL;
93
94        if ((bioF = BIO_new(BIO_f_base64())) == NULL) {
95            BIO_free(bioS);
96            return NULL;
97        }
98        bioS = BIO_push(bioF, bioS);
99        rc = d2i_X509_bio(bioS, NULL);
100        BIO_free_all(bioS);
101
102        if (rc == NULL) {
103            /* 3. try plain DER */
104            if ((bioS=BIO_new_file(filename, "r")) == NULL)
105                return NULL;
106            rc = d2i_X509_bio(bioS, NULL);
107            BIO_free(bioS);
108        }
109    }
110    if (rc != NULL && x509 != NULL) {
111        if (*x509 != NULL)
112            X509_free(*x509);
113        *x509 = rc;
114    }
115    return rc;
116}
117
118#if SSL_LIBRARY_VERSION <= 0x00904100
119static EVP_PKEY *d2i_PrivateKey_bio(BIO *bio, EVP_PKEY **key)
120{
121     return ((EVP_PKEY *)ASN1_d2i_bio(
122             (char *(*)())EVP_PKEY_new,
123             (char *(*)())d2i_PrivateKey,
124             (bio), (unsigned char **)(key)));
125}
126#endif
127
128EVP_PKEY *SSL_read_PrivateKey(char* filename, EVP_PKEY **key, modssl_read_bio_cb_fn *cb, void *s)
129{
130    EVP_PKEY *rc;
131    BIO *bioS;
132    BIO *bioF;
133
134    /* 1. try PEM (= DER+Base64+headers) */
135    if ((bioS=BIO_new_file(filename, "r")) == NULL)
136        return NULL;
137    rc = modssl_PEM_read_bio_PrivateKey(bioS, key, cb, s);
138    BIO_free(bioS);
139
140    if (rc == NULL) {
141        /* 2. try DER+Base64 */
142        if ((bioS = BIO_new_file(filename, "r")) == NULL)
143            return NULL;
144
145        if ((bioF = BIO_new(BIO_f_base64())) == NULL) {
146            BIO_free(bioS);
147            return NULL;
148        }
149        bioS = BIO_push(bioF, bioS);
150        rc = d2i_PrivateKey_bio(bioS, NULL);
151        BIO_free_all(bioS);
152
153        if (rc == NULL) {
154            /* 3. try plain DER */
155            if ((bioS = BIO_new_file(filename, "r")) == NULL)
156                return NULL;
157            rc = d2i_PrivateKey_bio(bioS, NULL);
158            BIO_free(bioS);
159        }
160    }
161    if (rc != NULL && key != NULL) {
162        if (*key != NULL)
163            EVP_PKEY_free(*key);
164        *key = rc;
165    }
166    return rc;
167}
168
169/*  _________________________________________________________________
170**
171**  Smart shutdown
172**  _________________________________________________________________
173*/
174
175int SSL_smart_shutdown(SSL *ssl)
176{
177    int i;
178    int rc;
179
180    /*
181     * Repeat the calls, because SSL_shutdown internally dispatches through a
182     * little state machine. Usually only one or two interation should be
183     * needed, so we restrict the total number of restrictions in order to
184     * avoid process hangs in case the client played bad with the socket
185     * connection and OpenSSL cannot recognize it.
186     */
187    rc = 0;
188    for (i = 0; i < 4 /* max 2x pending + 2x data = 4 */; i++) {
189        if ((rc = SSL_shutdown(ssl)))
190            break;
191    }
192    return rc;
193}
194
195/*  _________________________________________________________________
196**
197**  Certificate Revocation List (CRL) Storage
198**  _________________________________________________________________
199*/
200
201X509_STORE *SSL_X509_STORE_create(char *cpFile, char *cpPath)
202{
203    X509_STORE *pStore;
204    X509_LOOKUP *pLookup;
205    int rv = 1;
206
207    ERR_clear_error();
208
209    if (cpFile == NULL && cpPath == NULL)
210        return NULL;
211    if ((pStore = X509_STORE_new()) == NULL)
212        return NULL;
213    if (cpFile != NULL) {
214        pLookup = X509_STORE_add_lookup(pStore, X509_LOOKUP_file());
215        if (pLookup == NULL) {
216            X509_STORE_free(pStore);
217            return NULL;
218        }
219        rv = X509_LOOKUP_load_file(pLookup, cpFile, X509_FILETYPE_PEM);
220    }
221    if (cpPath != NULL && rv == 1) {
222        pLookup = X509_STORE_add_lookup(pStore, X509_LOOKUP_hash_dir());
223        if (pLookup == NULL) {
224            X509_STORE_free(pStore);
225            return NULL;
226        }
227        rv = X509_LOOKUP_add_dir(pLookup, cpPath, X509_FILETYPE_PEM);
228    }
229    return rv == 1 ? pStore : NULL;
230}
231
232int SSL_X509_STORE_lookup(X509_STORE *pStore, int nType,
233                          X509_NAME *pName, X509_OBJECT *pObj)
234{
235    X509_STORE_CTX pStoreCtx;
236    int rc;
237
238    X509_STORE_CTX_init(&pStoreCtx, pStore, NULL, NULL);
239    rc = X509_STORE_get_by_subject(&pStoreCtx, nType, pName, pObj);
240    X509_STORE_CTX_cleanup(&pStoreCtx);
241    return rc;
242}
243
244/*  _________________________________________________________________
245**
246**  Cipher Suite Spec String Creation
247**  _________________________________________________________________
248*/
249
250char *SSL_make_ciphersuite(apr_pool_t *p, SSL *ssl)
251{
252    STACK_OF(SSL_CIPHER) *sk;
253    SSL_CIPHER *c;
254    int i;
255    int l;
256    char *cpCipherSuite;
257    char *cp;
258
259    if (ssl == NULL)
260        return "";
261    if ((sk = (STACK_OF(SSL_CIPHER) *)SSL_get_ciphers(ssl)) == NULL)
262        return "";
263    l = 0;
264    for (i = 0; i < sk_SSL_CIPHER_num(sk); i++) {
265        c = sk_SSL_CIPHER_value(sk, i);
266        l += strlen(SSL_CIPHER_get_name(c))+2+1;
267    }
268    if (l == 0)
269        return "";
270    cpCipherSuite = (char *)apr_palloc(p, l+1);
271    cp = cpCipherSuite;
272    for (i = 0; i < sk_SSL_CIPHER_num(sk); i++) {
273        c = sk_SSL_CIPHER_value(sk, i);
274        l = strlen(SSL_CIPHER_get_name(c));
275        memcpy(cp, SSL_CIPHER_get_name(c), l);
276        cp += l;
277        *cp++ = '/';
278        *cp++ = (SSL_CIPHER_get_valid(c) == 1 ? '1' : '0');
279        *cp++ = ':';
280    }
281    *(cp-1) = NUL;
282    return cpCipherSuite;
283}
284
285/*  _________________________________________________________________
286**
287**  Certificate Checks
288**  _________________________________________________________________
289*/
290
291/* check whether cert contains extended key usage with a SGC tag */
292BOOL SSL_X509_isSGC(X509 *cert)
293{
294#ifdef HAVE_SSL_X509V3_EXT_d2i
295    X509_EXTENSION *ext;
296    int ext_nid;
297    EXTENDED_KEY_USAGE *sk;
298    BOOL is_sgc;
299    int idx;
300    int i;
301
302    is_sgc = FALSE;
303    idx = X509_get_ext_by_NID(cert, NID_ext_key_usage, -1);
304    if (idx >= 0) {
305        ext = X509_get_ext(cert, idx);
306        if ((sk = (EXTENDED_KEY_USAGE *)X509V3_EXT_d2i(ext)) != NULL) {
307            for (i = 0; i < sk_ASN1_OBJECT_num(sk); i++) {
308                ext_nid = OBJ_obj2nid((ASN1_OBJECT *)sk_ASN1_OBJECT_value(sk, i));
309                if (ext_nid == NID_ms_sgc || ext_nid == NID_ns_sgc) {
310                    is_sgc = TRUE;
311                    break;
312                }
313            }
314        }
315    }
316    return is_sgc;
317#else
318    return FALSE;
319#endif
320}
321
322/* retrieve basic constraints ingredients */
323BOOL SSL_X509_getBC(X509 *cert, int *ca, int *pathlen)
324{
325#ifdef HAVE_SSL_X509V3_EXT_d2i
326    X509_EXTENSION *ext;
327    BASIC_CONSTRAINTS *bc;
328    int idx;
329    BIGNUM *bn = NULL;
330    char *cp;
331
332    if ((idx = X509_get_ext_by_NID(cert, NID_basic_constraints, -1)) < 0)
333        return FALSE;
334    ext = X509_get_ext(cert, idx);
335    if (ext == NULL)
336        return FALSE;
337    if ((bc = (BASIC_CONSTRAINTS *)X509V3_EXT_d2i(ext)) == NULL)
338        return FALSE;
339    *ca = bc->ca;
340    *pathlen = -1 /* unlimited */;
341    if (bc->pathlen != NULL) {
342        if ((bn = ASN1_INTEGER_to_BN(bc->pathlen, NULL)) == NULL)
343            return FALSE;
344        if ((cp = BN_bn2dec(bn)) == NULL)
345            return FALSE;
346        *pathlen = atoi(cp);
347        free(cp);
348        BN_free(bn);
349    }
350    BASIC_CONSTRAINTS_free(bc);
351    return TRUE;
352#else
353    return FALSE;
354#endif
355}
356
357/* retrieve subject CommonName of certificate */
358BOOL SSL_X509_getCN(apr_pool_t *p, X509 *xs, char **cppCN)
359{
360    X509_NAME *xsn;
361    X509_NAME_ENTRY *xsne;
362    int i, nid;
363    unsigned char *data_ptr;
364    int data_len;
365
366    xsn = X509_get_subject_name(xs);
367    for (i = 0; i < sk_X509_NAME_ENTRY_num((STACK_OF(X509_NAME_ENTRY) *)
368                                           X509_NAME_get_entries(xsn)); i++) {
369        xsne = sk_X509_NAME_ENTRY_value((STACK_OF(X509_NAME_ENTRY) *)
370                                         X509_NAME_get_entries(xsn), i);
371        nid = OBJ_obj2nid((ASN1_OBJECT *)X509_NAME_ENTRY_get_object(xsne));
372        if (nid == NID_commonName) {
373            data_ptr = X509_NAME_ENTRY_get_data_ptr(xsne);
374            data_len = X509_NAME_ENTRY_get_data_len(xsne);
375            *cppCN = apr_palloc(p, data_len+1);
376            apr_cpystrn(*cppCN, (char *)data_ptr, data_len+1);
377            (*cppCN)[data_len] = NUL;
378            ap_xlate_proto_from_ascii(*cppCN, data_len);
379            return TRUE;
380        }
381    }
382    return FALSE;
383}
384
385/*
386 * convert an X509_NAME to an RFC 2253 formatted string, optionally truncated
387 * to maxlen characters (specify a maxlen of 0 for no length limit)
388 */
389char *SSL_X509_NAME_to_string(apr_pool_t *p, X509_NAME *dn, unsigned int maxlen)
390{
391    char *result = NULL;
392    BIO *bio;
393    int len;
394
395    if ((bio = BIO_new(BIO_s_mem())) == NULL)
396        return NULL;
397    X509_NAME_print_ex(bio, dn, 0, XN_FLAG_RFC2253);
398    len = BIO_pending(bio);
399    if (len > 0) {
400        result = apr_palloc(p, maxlen ? maxlen+1 : len+1);
401        if (maxlen && maxlen < len) {
402            len = BIO_read(bio, result, maxlen);
403            if (maxlen > 2) {
404                /* insert trailing ellipsis if there's enough space */
405                apr_snprintf(result + maxlen - 3, 4, "...");
406            }
407        } else {
408            len = BIO_read(bio, result, len);
409        }
410        result[len] = NUL;
411    }
412    BIO_free(bio);
413
414    return result;
415}
416
417/*  _________________________________________________________________
418**
419**  Low-Level CA Certificate Loading
420**  _________________________________________________________________
421*/
422
423BOOL SSL_X509_INFO_load_file(apr_pool_t *ptemp,
424                             STACK_OF(X509_INFO) *sk,
425                             const char *filename)
426{
427    BIO *in;
428
429    if (!(in = BIO_new(BIO_s_file()))) {
430        return FALSE;
431    }
432
433    if (BIO_read_filename(in, MODSSL_PCHAR_CAST filename) <= 0) {
434        BIO_free(in);
435        return FALSE;
436    }
437
438    ERR_clear_error();
439
440    modssl_PEM_X509_INFO_read_bio(in, sk, NULL, NULL);
441
442    BIO_free(in);
443
444    return TRUE;
445}
446
447BOOL SSL_X509_INFO_load_path(apr_pool_t *ptemp,
448                             STACK_OF(X509_INFO) *sk,
449                             const char *pathname)
450{
451    /* XXX: this dir read code is exactly the same as that in
452     * ssl_engine_init.c, only the call to handle the fullname is different,
453     * should fold the duplication.
454     */
455    apr_dir_t *dir;
456    apr_finfo_t dirent;
457    apr_int32_t finfo_flags = APR_FINFO_TYPE|APR_FINFO_NAME;
458    const char *fullname;
459    BOOL ok = FALSE;
460
461    if (apr_dir_open(&dir, pathname, ptemp) != APR_SUCCESS) {
462        return FALSE;
463    }
464
465    while ((apr_dir_read(&dirent, finfo_flags, dir)) == APR_SUCCESS) {
466        if (dirent.filetype == APR_DIR) {
467            continue; /* don't try to load directories */
468        }
469
470        fullname = apr_pstrcat(ptemp,
471                               pathname, "/", dirent.name,
472                               NULL);
473
474        if (SSL_X509_INFO_load_file(ptemp, sk, fullname)) {
475            ok = TRUE;
476        }
477    }
478
479    apr_dir_close(dir);
480
481    return ok;
482}
483
484/*  _________________________________________________________________
485**
486**  Extra Server Certificate Chain Support
487**  _________________________________________________________________
488*/
489
490/*
491 * Read a file that optionally contains the server certificate in PEM
492 * format, possibly followed by a sequence of CA certificates that
493 * should be sent to the peer in the SSL Certificate message.
494 */
495int SSL_CTX_use_certificate_chain(
496    SSL_CTX *ctx, char *file, int skipfirst, modssl_read_bio_cb_fn *cb)
497{
498    BIO *bio;
499    X509 *x509;
500    unsigned long err;
501    int n;
502    STACK_OF(X509) *extra_certs;
503
504    if ((bio = BIO_new(BIO_s_file_internal())) == NULL)
505        return -1;
506    if (BIO_read_filename(bio, file) <= 0) {
507        BIO_free(bio);
508        return -1;
509    }
510    /* optionally skip a leading server certificate */
511    if (skipfirst) {
512        if ((x509 = modssl_PEM_read_bio_X509(bio, NULL, cb, NULL)) == NULL) {
513            BIO_free(bio);
514            return -1;
515        }
516        X509_free(x509);
517    }
518    /* free a perhaps already configured extra chain */
519    extra_certs=SSL_CTX_get_extra_certs(ctx);
520    if (extra_certs != NULL) {
521        sk_X509_pop_free((STACK_OF(X509) *)extra_certs, X509_free);
522        SSL_CTX_set_extra_certs(ctx,NULL);
523    }
524    /* create new extra chain by loading the certs */
525    n = 0;
526    while ((x509 = modssl_PEM_read_bio_X509(bio, NULL, cb, NULL)) != NULL) {
527        if (!SSL_CTX_add_extra_chain_cert(ctx, x509)) {
528            X509_free(x509);
529            BIO_free(bio);
530            return -1;
531        }
532        n++;
533    }
534    /* Make sure that only the error is just an EOF */
535    if ((err = ERR_peek_error()) > 0) {
536        if (!(   ERR_GET_LIB(err) == ERR_LIB_PEM
537              && ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) {
538            BIO_free(bio);
539            return -1;
540        }
541        while (ERR_get_error() > 0) ;
542    }
543    BIO_free(bio);
544    return n;
545}
546
547/*  _________________________________________________________________
548**
549**  Session Stuff
550**  _________________________________________________________________
551*/
552
553char *SSL_SESSION_id2sz(unsigned char *id, int idlen,
554                        char *str, int strsize)
555{
556    char *cp;
557    int n;
558
559    cp = str;
560    for (n = 0; n < idlen && n < SSL_MAX_SSL_SESSION_ID_LENGTH; n++) {
561        apr_snprintf(cp, strsize - (cp-str), "%02X", id[n]);
562        cp += 2;
563    }
564    *cp = NUL;
565    return str;
566}
567
568/* sslc+OpenSSL compat */
569
570int modssl_session_get_time(SSL_SESSION *session)
571{
572#ifdef OPENSSL_VERSION_NUMBER
573    return SSL_SESSION_get_time(session);
574#else /* assume sslc */
575    CRYPTO_TIME_T ct;
576    SSL_SESSION_get_time(session, &ct);
577    return CRYPTO_time_to_int(&ct);
578#endif
579}
580
581#ifndef SSLC_VERSION_NUMBER
582#define SSLC_VERSION_NUMBER 0x0000
583#endif
584
585DH *modssl_dh_configure(unsigned char *p, int plen,
586                        unsigned char *g, int glen)
587{
588    DH *dh;
589
590    if (!(dh = DH_new())) {
591        return NULL;
592    }
593
594#if defined(OPENSSL_VERSION_NUMBER) || (SSLC_VERSION_NUMBER < 0x2000)
595    dh->p = BN_bin2bn(p, plen, NULL);
596    dh->g = BN_bin2bn(g, glen, NULL);
597    if (!(dh->p && dh->g)) {
598        DH_free(dh);
599        return NULL;
600    }
601#else
602    R_EITEMS_add(dh->data, PK_TYPE_DH, PK_DH_P, 0, p, plen, R_EITEMS_PF_COPY);
603    R_EITEMS_add(dh->data, PK_TYPE_DH, PK_DH_G, 0, g, glen, R_EITEMS_PF_COPY);
604#endif
605
606    return dh;
607}
608