diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2016-12-05 22:19:16 +0300 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2016-12-05 22:19:16 +0300 |
commit | 89e9332e2bacdba1cf44aabfcfc082c0de62871c (patch) | |
tree | 156ad5e5b00e6966642b2d600dafa5f0cc1d43ac /modules/ssl/ssl_util_ssl.c | |
parent | f51547f19e44fc1f511837443cb92ba28c189b9c (diff) | |
parent | adb6f181257af28ee67af15fc49d2699a0080d4c (diff) | |
download | apache2-89e9332e2bacdba1cf44aabfcfc082c0de62871c.tar.gz |
Merge branch 'master' of git://anonscm.debian.org/pkg-apache/apache2
Diffstat (limited to 'modules/ssl/ssl_util_ssl.c')
-rw-r--r-- | modules/ssl/ssl_util_ssl.c | 346 |
1 files changed, 157 insertions, 189 deletions
diff --git a/modules/ssl/ssl_util_ssl.c b/modules/ssl/ssl_util_ssl.c index 0bf37768..a7607c73 100644 --- a/modules/ssl/ssl_util_ssl.c +++ b/modules/ssl/ssl_util_ssl.c @@ -38,33 +38,33 @@ * also note that OpenSSL increments at static variable when * SSL_get_ex_new_index() is called, so we _must_ do this at startup. */ -static int SSL_app_data2_idx = -1; +static int app_data2_idx = -1; -void SSL_init_app_data2_idx(void) +void modssl_init_app_data2_idx(void) { int i; - if (SSL_app_data2_idx > -1) { + if (app_data2_idx > -1) { return; } /* we _do_ need to call this twice */ - for (i=0; i<=1; i++) { - SSL_app_data2_idx = + for (i = 0; i <= 1; i++) { + app_data2_idx = SSL_get_ex_new_index(0, "Second Application Data for SSL", NULL, NULL, NULL); } } -void *SSL_get_app_data2(SSL *ssl) +void *modssl_get_app_data2(SSL *ssl) { - return (void *)SSL_get_ex_data(ssl, SSL_app_data2_idx); + return (void *)SSL_get_ex_data(ssl, app_data2_idx); } -void SSL_set_app_data2(SSL *ssl, void *arg) +void modssl_set_app_data2(SSL *ssl, void *arg) { - SSL_set_ex_data(ssl, SSL_app_data2_idx, (char *)arg); + SSL_set_ex_data(ssl, app_data2_idx, (char *)arg); return; } @@ -74,7 +74,7 @@ void SSL_set_app_data2(SSL *ssl, void *arg) ** _________________________________________________________________ */ -EVP_PKEY *SSL_read_PrivateKey(const char* filename, EVP_PKEY **key, pem_password_cb *cb, void *s) +EVP_PKEY *modssl_read_privatekey(const char* filename, EVP_PKEY **key, pem_password_cb *cb, void *s) { EVP_PKEY *rc; BIO *bioS; @@ -121,10 +121,11 @@ EVP_PKEY *SSL_read_PrivateKey(const char* filename, EVP_PKEY **key, pem_password ** _________________________________________________________________ */ -int SSL_smart_shutdown(SSL *ssl) +int modssl_smart_shutdown(SSL *ssl) { int i; int rc; + int flush; /* * Repeat the calls, because SSL_shutdown internally dispatches through a @@ -134,8 +135,20 @@ int SSL_smart_shutdown(SSL *ssl) * connection and OpenSSL cannot recognize it. */ rc = 0; + flush = !(SSL_get_shutdown(ssl) & SSL_SENT_SHUTDOWN); for (i = 0; i < 4 /* max 2x pending + 2x data = 4 */; i++) { - if ((rc = SSL_shutdown(ssl))) + rc = SSL_shutdown(ssl); + if (rc >= 0 && flush && (SSL_get_shutdown(ssl) & SSL_SENT_SHUTDOWN)) { + /* Once the close notity is sent through the output filters, + * ensure it is flushed through the socket. + */ + if (BIO_flush(SSL_get_wbio(ssl)) <= 0) { + rc = -1; + break; + } + flush = 0; + } + if (rc != 0) break; } return rc; @@ -148,7 +161,7 @@ int SSL_smart_shutdown(SSL *ssl) */ /* retrieve basic constraints ingredients */ -BOOL SSL_X509_getBC(X509 *cert, int *ca, int *pathlen) +BOOL modssl_X509_getBC(X509 *cert, int *ca, int *pathlen) { BASIC_CONSTRAINTS *bc; BIGNUM *bn = NULL; @@ -160,34 +173,49 @@ BOOL SSL_X509_getBC(X509 *cert, int *ca, int *pathlen) *ca = bc->ca; *pathlen = -1 /* unlimited */; if (bc->pathlen != NULL) { - if ((bn = ASN1_INTEGER_to_BN(bc->pathlen, NULL)) == NULL) + if ((bn = ASN1_INTEGER_to_BN(bc->pathlen, NULL)) == NULL) { + BASIC_CONSTRAINTS_free(bc); return FALSE; - if ((cp = BN_bn2dec(bn)) == NULL) + } + if ((cp = BN_bn2dec(bn)) == NULL) { + BN_free(bn); + BASIC_CONSTRAINTS_free(bc); return FALSE; + } *pathlen = atoi(cp); - free(cp); + OPENSSL_free(cp); BN_free(bn); } BASIC_CONSTRAINTS_free(bc); return TRUE; } -/* convert a NAME_ENTRY to UTF8 string */ -char *SSL_X509_NAME_ENTRY_to_string(apr_pool_t *p, X509_NAME_ENTRY *xsne) +/* convert an ASN.1 string to a UTF-8 string (escaping control characters) */ +static char *asn1_string_to_utf8(apr_pool_t *p, ASN1_STRING *asn1str) { char *result = NULL; - BIO* bio; + BIO *bio; int len; if ((bio = BIO_new(BIO_s_mem())) == NULL) return NULL; - ASN1_STRING_print_ex(bio, X509_NAME_ENTRY_get_data(xsne), - ASN1_STRFLGS_ESC_CTRL|ASN1_STRFLGS_UTF8_CONVERT); + + ASN1_STRING_print_ex(bio, asn1str, ASN1_STRFLGS_ESC_CTRL| + ASN1_STRFLGS_UTF8_CONVERT); len = BIO_pending(bio); - result = apr_palloc(p, len+1); - len = BIO_read(bio, result, len); - result[len] = NUL; + if (len > 0) { + result = apr_palloc(p, len+1); + len = BIO_read(bio, result, len); + result[len] = NUL; + } BIO_free(bio); + return result; +} + +/* convert a NAME_ENTRY to UTF8 string */ +char *modssl_X509_NAME_ENTRY_to_string(apr_pool_t *p, X509_NAME_ENTRY *xsne) +{ + char *result = asn1_string_to_utf8(p, X509_NAME_ENTRY_get_data(xsne)); ap_xlate_proto_from_ascii(result, len); return result; } @@ -196,7 +224,7 @@ char *SSL_X509_NAME_ENTRY_to_string(apr_pool_t *p, X509_NAME_ENTRY *xsne) * convert an X509_NAME to an RFC 2253 formatted string, optionally truncated * to maxlen characters (specify a maxlen of 0 for no length limit) */ -char *SSL_X509_NAME_to_string(apr_pool_t *p, X509_NAME *dn, int maxlen) +char *modssl_X509_NAME_to_string(apr_pool_t *p, X509_NAME *dn, int maxlen) { char *result = NULL; BIO *bio; @@ -224,51 +252,123 @@ char *SSL_X509_NAME_to_string(apr_pool_t *p, X509_NAME *dn, int maxlen) return result; } -/* return an array of (RFC 6125 coined) DNS-IDs and CN-IDs in a certificate */ -BOOL SSL_X509_getIDs(apr_pool_t *p, X509 *x509, apr_array_header_t **ids) +static void parse_otherName_value(apr_pool_t *p, ASN1_TYPE *value, + const char *onf, apr_array_header_t **entries) +{ + const char *str; + int nid = onf ? OBJ_txt2nid(onf) : NID_undef; + + if (!value || (nid == NID_undef) || !*entries) + return; + + /* + * Currently supported otherName forms (values for "onf"): + * "msUPN" (1.3.6.1.4.1.311.20.2.3): Microsoft User Principal Name + * "id-on-dnsSRV" (1.3.6.1.5.5.7.8.7): SRVName, as specified in RFC 4985 + */ + if ((nid == NID_ms_upn) && (value->type == V_ASN1_UTF8STRING) && + (str = asn1_string_to_utf8(p, value->value.utf8string))) { + APR_ARRAY_PUSH(*entries, const char *) = str; + } else if (strEQ(onf, "id-on-dnsSRV") && + (value->type == V_ASN1_IA5STRING) && + (str = asn1_string_to_utf8(p, value->value.ia5string))) { + APR_ARRAY_PUSH(*entries, const char *) = str; + } +} + +/* + * Return an array of subjectAltName entries of type "type". If idx is -1, + * return all entries of the given type, otherwise return an array consisting + * of the n-th occurrence of that type only. Currently supported types: + * GEN_EMAIL (rfc822Name) + * GEN_DNS (dNSName) + * GEN_OTHERNAME (requires the otherName form ["onf"] argument to be supplied, + * see parse_otherName_value for the currently supported forms) + */ +BOOL modssl_X509_getSAN(apr_pool_t *p, X509 *x509, int type, const char *onf, + int idx, apr_array_header_t **entries) { STACK_OF(GENERAL_NAME) *names; - BIO *bio; - X509_NAME *subj; - char **cpp; - int i, n; + int nid = onf ? OBJ_txt2nid(onf) : NID_undef; - if (!x509 || !(*ids = apr_array_make(p, 0, sizeof(char *)))) { - *ids = NULL; + if (!x509 || (type < GEN_OTHERNAME) || + ((type == GEN_OTHERNAME) && (nid == NID_undef)) || + (type > GEN_RID) || (idx < -1) || + !(*entries = apr_array_make(p, 0, sizeof(char *)))) { + *entries = NULL; return FALSE; } - /* First, the DNS-IDs (dNSName entries in the subjectAltName extension) */ - if ((names = X509_get_ext_d2i(x509, NID_subject_alt_name, NULL, NULL)) && - (bio = BIO_new(BIO_s_mem()))) { + if ((names = X509_get_ext_d2i(x509, NID_subject_alt_name, NULL, NULL))) { + int i, n = 0; GENERAL_NAME *name; + const char *utf8str; for (i = 0; i < sk_GENERAL_NAME_num(names); i++) { name = sk_GENERAL_NAME_value(names, i); - if (name->type == GEN_DNS) { - ASN1_STRING_print_ex(bio, name->d.ia5, ASN1_STRFLGS_ESC_CTRL| - ASN1_STRFLGS_UTF8_CONVERT); - n = BIO_pending(bio); - if (n > 0) { - cpp = (char **)apr_array_push(*ids); - *cpp = apr_palloc(p, n+1); - n = BIO_read(bio, *cpp, n); - (*cpp)[n] = NUL; + + if (name->type != type) + continue; + + switch (type) { + case GEN_EMAIL: + case GEN_DNS: + if (((idx == -1) || (n == idx)) && + (utf8str = asn1_string_to_utf8(p, name->d.ia5))) { + APR_ARRAY_PUSH(*entries, const char *) = utf8str; } + n++; + break; + case GEN_OTHERNAME: + if (OBJ_obj2nid(name->d.otherName->type_id) == nid) { + if (((idx == -1) || (n == idx))) { + parse_otherName_value(p, name->d.otherName->value, + onf, entries); + } + n++; + } + break; + default: + /* + * Not implemented right now: + * GEN_X400 (x400Address) + * GEN_DIRNAME (directoryName) + * GEN_EDIPARTY (ediPartyName) + * GEN_URI (uniformResourceIdentifier) + * GEN_IPADD (iPAddress) + * GEN_RID (registeredID) + */ + break; } + + if ((idx != -1) && (n > idx)) + break; } - BIO_free(bio); - } - if (names) sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free); + } + + return apr_is_empty_array(*entries) ? FALSE : TRUE; +} + +/* return an array of (RFC 6125 coined) DNS-IDs and CN-IDs in a certificate */ +static BOOL getIDs(apr_pool_t *p, X509 *x509, apr_array_header_t **ids) +{ + X509_NAME *subj; + int i = -1; + + /* First, the DNS-IDs (dNSName entries in the subjectAltName extension) */ + if (!x509 || + (modssl_X509_getSAN(p, x509, GEN_DNS, NULL, -1, ids) == FALSE && !*ids)) { + *ids = NULL; + return FALSE; + } /* Second, the CN-IDs (commonName attributes in the subject DN) */ subj = X509_get_subject_name(x509); - i = -1; while ((i = X509_NAME_get_index_by_NID(subj, NID_commonName, i)) != -1) { - cpp = (char **)apr_array_push(*ids); - *cpp = SSL_X509_NAME_ENTRY_to_string(p, X509_NAME_get_entry(subj, i)); + APR_ARRAY_PUSH(*ids, const char *) = + modssl_X509_NAME_ENTRY_to_string(p, X509_NAME_get_entry(subj, i)); } return apr_is_empty_array(*ids) ? FALSE : TRUE; @@ -279,8 +379,8 @@ BOOL SSL_X509_getIDs(apr_pool_t *p, X509 *x509, apr_array_header_t **ids) * DNS-IDs and CN-IDs (RFC 6125), optionally with basic wildcard matching. * If server_rec is non-NULL, some (debug/trace) logging is enabled. */ -BOOL SSL_X509_match_name(apr_pool_t *p, X509 *x509, const char *name, - BOOL allow_wildcard, server_rec *s) +BOOL modssl_X509_match_name(apr_pool_t *p, X509 *x509, const char *name, + BOOL allow_wildcard, server_rec *s) { BOOL matched = FALSE; apr_array_header_t *ids; @@ -295,7 +395,7 @@ BOOL SSL_X509_match_name(apr_pool_t *p, X509 *x509, const char *name, * is found). */ - if (SSL_X509_getIDs(p, x509, &ids)) { + if (getIDs(p, x509, &ids)) { const char *cp; int i; char **id = (char **)ids->elts; @@ -326,7 +426,7 @@ BOOL SSL_X509_match_name(apr_pool_t *p, X509 *x509, const char *name, if (s) { ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, s, - "[%s] SSL_X509_match_name: expecting name '%s', " + "[%s] modssl_X509_match_name: expecting name '%s', " "%smatched by ID '%s'", (mySrvConfig(s))->vhost_id, name, matched == TRUE ? "" : "NOT ", id[i]); @@ -352,73 +452,6 @@ BOOL SSL_X509_match_name(apr_pool_t *p, X509 *x509, const char *name, /* _________________________________________________________________ ** -** Low-Level CA Certificate Loading -** _________________________________________________________________ -*/ - -BOOL SSL_X509_INFO_load_file(apr_pool_t *ptemp, - STACK_OF(X509_INFO) *sk, - const char *filename) -{ - BIO *in; - - if (!(in = BIO_new(BIO_s_file()))) { - return FALSE; - } - - if (BIO_read_filename(in, filename) <= 0) { - BIO_free(in); - return FALSE; - } - - ERR_clear_error(); - - PEM_X509_INFO_read_bio(in, sk, NULL, NULL); - - BIO_free(in); - - return TRUE; -} - -BOOL SSL_X509_INFO_load_path(apr_pool_t *ptemp, - STACK_OF(X509_INFO) *sk, - const char *pathname) -{ - /* XXX: this dir read code is exactly the same as that in - * ssl_engine_init.c, only the call to handle the fullname is different, - * should fold the duplication. - */ - apr_dir_t *dir; - apr_finfo_t dirent; - apr_int32_t finfo_flags = APR_FINFO_TYPE|APR_FINFO_NAME; - const char *fullname; - BOOL ok = FALSE; - - if (apr_dir_open(&dir, pathname, ptemp) != APR_SUCCESS) { - return FALSE; - } - - while ((apr_dir_read(&dirent, finfo_flags, dir)) == APR_SUCCESS) { - if (dirent.filetype == APR_DIR) { - continue; /* don't try to load directories */ - } - - fullname = apr_pstrcat(ptemp, - pathname, "/", dirent.name, - NULL); - - if (SSL_X509_INFO_load_file(ptemp, sk, fullname)) { - ok = TRUE; - } - } - - apr_dir_close(dir); - - return ok; -} - -/* _________________________________________________________________ -** ** Custom (EC)DH parameter support ** _________________________________________________________________ */ @@ -451,77 +484,12 @@ EC_GROUP *ssl_ec_GetParamFromFile(const char *file) /* _________________________________________________________________ ** -** Extra Server Certificate Chain Support -** _________________________________________________________________ -*/ - -/* - * Read a file that optionally contains the server certificate in PEM - * format, possibly followed by a sequence of CA certificates that - * should be sent to the peer in the SSL Certificate message. - */ -int SSL_CTX_use_certificate_chain( - SSL_CTX *ctx, char *file, int skipfirst, pem_password_cb *cb) -{ - BIO *bio; - X509 *x509; - unsigned long err; - int n; - - if ((bio = BIO_new(BIO_s_file_internal())) == NULL) - return -1; - if (BIO_read_filename(bio, file) <= 0) { - BIO_free(bio); - return -1; - } - /* optionally skip a leading server certificate */ - if (skipfirst) { - if ((x509 = PEM_read_bio_X509(bio, NULL, cb, NULL)) == NULL) { - BIO_free(bio); - return -1; - } - X509_free(x509); - } - /* free a perhaps already configured extra chain */ -#ifdef OPENSSL_NO_SSL_INTERN - SSL_CTX_clear_extra_chain_certs(ctx); -#else - if (ctx->extra_certs != NULL) { - sk_X509_pop_free((STACK_OF(X509) *)ctx->extra_certs, X509_free); - ctx->extra_certs = NULL; - } -#endif - /* create new extra chain by loading the certs */ - n = 0; - while ((x509 = PEM_read_bio_X509(bio, NULL, cb, NULL)) != NULL) { - if (!SSL_CTX_add_extra_chain_cert(ctx, x509)) { - X509_free(x509); - BIO_free(bio); - return -1; - } - n++; - } - /* Make sure that only the error is just an EOF */ - if ((err = ERR_peek_error()) > 0) { - if (!( ERR_GET_LIB(err) == ERR_LIB_PEM - && ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) { - BIO_free(bio); - return -1; - } - while (ERR_get_error() > 0) ; - } - BIO_free(bio); - return n; -} - -/* _________________________________________________________________ -** ** Session Stuff ** _________________________________________________________________ */ -char *SSL_SESSION_id2sz(unsigned char *id, int idlen, - char *str, int strsize) +char *modssl_SSL_SESSION_id2sz(unsigned char *id, int idlen, + char *str, int strsize) { if (idlen > SSL_MAX_SSL_SESSION_ID_LENGTH) idlen = SSL_MAX_SSL_SESSION_ID_LENGTH; |