X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=ssl%2Fssl_rsa.c;h=2837624ae9e387590cba33fdc8ac17259f2defc6;hp=ba0c7f5117de6f7812d67d4af1fb0f512c3d85c4;hb=6da498991c43b23f2f0abc36338593c5492185f7;hpb=303c002898915c5636dfa9d295b9de38db65207a diff --git a/ssl/ssl_rsa.c b/ssl/ssl_rsa.c index ba0c7f5117..2837624ae9 100644 --- a/ssl/ssl_rsa.c +++ b/ssl/ssl_rsa.c @@ -57,15 +57,19 @@ */ #include +#include "ssl_locl.h" #include #include #include #include #include -#include "ssl_locl.h" static int ssl_set_cert(CERT *c, X509 *x509); static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey); +#ifndef OPENSSL_NO_TLSEXT +static int ssl_set_authz(CERT *c, unsigned char *authz, + size_t authz_length); +#endif int SSL_use_certificate(SSL *ssl, X509 *x) { if (x == NULL) @@ -73,7 +77,7 @@ int SSL_use_certificate(SSL *ssl, X509 *x) SSLerr(SSL_F_SSL_USE_CERTIFICATE,ERR_R_PASSED_NULL_PARAMETER); return(0); } - if (!ssl_cert_instantiate(&ssl->cert, ssl->ctx->default_cert)) + if (!ssl_cert_inst(&ssl->cert)) { SSLerr(SSL_F_SSL_USE_CERTIFICATE,ERR_R_MALLOC_FAILURE); return(0); @@ -81,7 +85,7 @@ int SSL_use_certificate(SSL *ssl, X509 *x) return(ssl_set_cert(ssl->cert,x)); } -#ifndef NO_STDIO +#ifndef OPENSSL_NO_STDIO int SSL_use_certificate_file(SSL *ssl, const char *file, int type) { int j; @@ -109,7 +113,7 @@ int SSL_use_certificate_file(SSL *ssl, const char *file, int type) else if (type == SSL_FILETYPE_PEM) { j=ERR_R_PEM_LIB; - x=PEM_read_bio_X509(in,NULL,ssl->ctx->default_passwd_callback); + x=PEM_read_bio_X509(in,NULL,ssl->ctx->default_passwd_callback,ssl->ctx->default_passwd_callback_userdata); } else { @@ -131,7 +135,7 @@ end: } #endif -int SSL_use_certificate_ASN1(SSL *ssl, unsigned char *d, int len) +int SSL_use_certificate_ASN1(SSL *ssl, const unsigned char *d, int len) { X509 *x; int ret; @@ -148,7 +152,7 @@ int SSL_use_certificate_ASN1(SSL *ssl, unsigned char *d, int len) return(ret); } -#ifndef NO_RSA +#ifndef OPENSSL_NO_RSA int SSL_use_RSAPrivateKey(SSL *ssl, RSA *rsa) { EVP_PKEY *pkey; @@ -159,7 +163,7 @@ int SSL_use_RSAPrivateKey(SSL *ssl, RSA *rsa) SSLerr(SSL_F_SSL_USE_RSAPRIVATEKEY,ERR_R_PASSED_NULL_PARAMETER); return(0); } - if (!ssl_cert_instantiate(&ssl->cert, ssl->ctx->default_cert)) + if (!ssl_cert_inst(&ssl->cert)) { SSLerr(SSL_F_SSL_USE_RSAPRIVATEKEY,ERR_R_MALLOC_FAILURE); return(0); @@ -170,7 +174,7 @@ int SSL_use_RSAPrivateKey(SSL *ssl, RSA *rsa) return(0); } - CRYPTO_add(&rsa->references,1,CRYPTO_LOCK_RSA); + RSA_up_ref(rsa); EVP_PKEY_assign_RSA(pkey,rsa); ret=ssl_set_pkey(ssl->cert,pkey); @@ -181,9 +185,24 @@ int SSL_use_RSAPrivateKey(SSL *ssl, RSA *rsa) static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey) { - int i,ok=0,bad=0; - - i=ssl_cert_type(NULL,pkey); + int i; + /* Special case for DH: check two DH certificate types for a match. + * This means for DH certificates we must set the certificate first. + */ + if (pkey->type == EVP_PKEY_DH) + { + X509 *x; + i = -1; + x = c->pkeys[SSL_PKEY_DH_RSA].x509; + if (x && X509_check_private_key(x, pkey)) + i = SSL_PKEY_DH_RSA; + x = c->pkeys[SSL_PKEY_DH_DSA].x509; + if (i == -1 && x && X509_check_private_key(x, pkey)) + i = SSL_PKEY_DH_DSA; + ERR_clear_error(); + } + else + i=ssl_cert_type(NULL,pkey); if (i < 0) { SSLerr(SSL_F_SSL_SET_PKEY,SSL_R_UNKNOWN_CERTIFICATE_TYPE); @@ -198,47 +217,20 @@ static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey) EVP_PKEY_free(pktmp); ERR_clear_error(); -#ifndef NO_RSA +#ifndef OPENSSL_NO_RSA /* Don't check the public/private key, this is mostly * for smart cards. */ if ((pkey->type == EVP_PKEY_RSA) && - (RSA_flags(pkey->pkey.rsa) & - RSA_METHOD_FLAG_NO_CHECK)) - ok=1; + (RSA_flags(pkey->pkey.rsa) & RSA_METHOD_FLAG_NO_CHECK)) + ; else #endif - if (!X509_check_private_key(c->pkeys[i].x509,pkey)) + if (!X509_check_private_key(c->pkeys[i].x509,pkey)) { - if ((i == SSL_PKEY_DH_RSA) || (i == SSL_PKEY_DH_DSA)) - { - i=(i == SSL_PKEY_DH_RSA)? - SSL_PKEY_DH_DSA:SSL_PKEY_DH_RSA; - - if (c->pkeys[i].x509 == NULL) - ok=1; - else - { - if (!X509_check_private_key( - c->pkeys[i].x509,pkey)) - bad=1; - else - ok=1; - } - } - else - bad=1; + X509_free(c->pkeys[i].x509); + c->pkeys[i].x509 = NULL; + return 0; } - else - ok=1; - } - else - ok=1; - - if (bad) - { - X509_free(c->pkeys[i].x509); - c->pkeys[i].x509=NULL; - return(0); } if (c->pkeys[i].privatekey != NULL) @@ -251,8 +243,8 @@ static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey) return(1); } -#ifndef NO_RSA -#ifndef NO_STDIO +#ifndef OPENSSL_NO_RSA +#ifndef OPENSSL_NO_STDIO int SSL_use_RSAPrivateKey_file(SSL *ssl, const char *file, int type) { int j,ret=0; @@ -280,7 +272,7 @@ int SSL_use_RSAPrivateKey_file(SSL *ssl, const char *file, int type) { j=ERR_R_PEM_LIB; rsa=PEM_read_bio_RSAPrivateKey(in,NULL, - ssl->ctx->default_passwd_callback); + ssl->ctx->default_passwd_callback,ssl->ctx->default_passwd_callback_userdata); } else { @@ -303,7 +295,7 @@ end: int SSL_use_RSAPrivateKey_ASN1(SSL *ssl, unsigned char *d, long len) { int ret; - unsigned char *p; + const unsigned char *p; RSA *rsa; p=d; @@ -317,7 +309,7 @@ int SSL_use_RSAPrivateKey_ASN1(SSL *ssl, unsigned char *d, long len) RSA_free(rsa); return(ret); } -#endif /* !NO_RSA */ +#endif /* !OPENSSL_NO_RSA */ int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey) { @@ -328,7 +320,7 @@ int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey) SSLerr(SSL_F_SSL_USE_PRIVATEKEY,ERR_R_PASSED_NULL_PARAMETER); return(0); } - if (!ssl_cert_instantiate(&ssl->cert, ssl->ctx->default_cert)) + if (!ssl_cert_inst(&ssl->cert)) { SSLerr(SSL_F_SSL_USE_PRIVATEKEY,ERR_R_MALLOC_FAILURE); return(0); @@ -337,7 +329,7 @@ int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey) return(ret); } -#ifndef NO_STDIO +#ifndef OPENSSL_NO_STDIO int SSL_use_PrivateKey_file(SSL *ssl, const char *file, int type) { int j,ret=0; @@ -360,7 +352,12 @@ int SSL_use_PrivateKey_file(SSL *ssl, const char *file, int type) { j=ERR_R_PEM_LIB; pkey=PEM_read_bio_PrivateKey(in,NULL, - ssl->ctx->default_passwd_callback); + ssl->ctx->default_passwd_callback,ssl->ctx->default_passwd_callback_userdata); + } + else if (type == SSL_FILETYPE_ASN1) + { + j = ERR_R_ASN1_LIB; + pkey = d2i_PrivateKey_bio(in,NULL); } else { @@ -380,10 +377,10 @@ end: } #endif -int SSL_use_PrivateKey_ASN1(int type, SSL *ssl, unsigned char *d, long len) +int SSL_use_PrivateKey_ASN1(int type, SSL *ssl, const unsigned char *d, long len) { int ret; - unsigned char *p; + const unsigned char *p; EVP_PKEY *pkey; p=d; @@ -405,18 +402,18 @@ int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x) SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE,ERR_R_PASSED_NULL_PARAMETER); return(0); } - if (!ssl_cert_instantiate(&ctx->default_cert, NULL)) + if (!ssl_cert_inst(&ctx->cert)) { SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE,ERR_R_MALLOC_FAILURE); return(0); } - return(ssl_set_cert(ctx->default_cert,x)); + return(ssl_set_cert(ctx->cert, x)); } static int ssl_set_cert(CERT *c, X509 *x) { EVP_PKEY *pkey; - int i,ok=0,bad=0; + int i; pkey=X509_get_pubkey(x); if (pkey == NULL) @@ -438,50 +435,29 @@ static int ssl_set_cert(CERT *c, X509 *x) EVP_PKEY_copy_parameters(pkey,c->pkeys[i].privatekey); ERR_clear_error(); -#ifndef NO_RSA +#ifndef OPENSSL_NO_RSA /* Don't check the public/private key, this is mostly * for smart cards. */ if ((c->pkeys[i].privatekey->type == EVP_PKEY_RSA) && (RSA_flags(c->pkeys[i].privatekey->pkey.rsa) & RSA_METHOD_FLAG_NO_CHECK)) - ok=1; + ; else -#endif - { +#endif /* OPENSSL_NO_RSA */ if (!X509_check_private_key(x,c->pkeys[i].privatekey)) { - if ((i == SSL_PKEY_DH_RSA) || (i == SSL_PKEY_DH_DSA)) - { - i=(i == SSL_PKEY_DH_RSA)? - SSL_PKEY_DH_DSA:SSL_PKEY_DH_RSA; - - if (c->pkeys[i].privatekey == NULL) - ok=1; - else - { - if (!X509_check_private_key(x, - c->pkeys[i].privatekey)) - bad=1; - else - ok=1; - } - } - else - bad=1; + /* don't fail for a cert/key mismatch, just free + * current private key (when switching to a different + * cert & key, first this function should be used, + * then ssl_set_pkey */ + EVP_PKEY_free(c->pkeys[i].privatekey); + c->pkeys[i].privatekey=NULL; + /* clear error queue */ + ERR_clear_error(); } - else - ok=1; - } /* NO_RSA */ } - else - ok=1; EVP_PKEY_free(pkey); - if (bad) - { - EVP_PKEY_free(c->pkeys[i].privatekey); - c->pkeys[i].privatekey=NULL; - } if (c->pkeys[i].x509 != NULL) X509_free(c->pkeys[i].x509); @@ -493,7 +469,7 @@ static int ssl_set_cert(CERT *c, X509 *x) return(1); } -#ifndef NO_STDIO +#ifndef OPENSSL_NO_STDIO int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type) { int j; @@ -521,7 +497,7 @@ int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type) else if (type == SSL_FILETYPE_PEM) { j=ERR_R_PEM_LIB; - x=PEM_read_bio_X509(in,NULL,ctx->default_passwd_callback); + x=PEM_read_bio_X509(in,NULL,ctx->default_passwd_callback,ctx->default_passwd_callback_userdata); } else { @@ -543,7 +519,7 @@ end: } #endif -int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, unsigned char *d) +int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, const unsigned char *d) { X509 *x; int ret; @@ -560,7 +536,7 @@ int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, unsigned char *d) return(ret); } -#ifndef NO_RSA +#ifndef OPENSSL_NO_RSA int SSL_CTX_use_RSAPrivateKey(SSL_CTX *ctx, RSA *rsa) { int ret; @@ -571,7 +547,7 @@ int SSL_CTX_use_RSAPrivateKey(SSL_CTX *ctx, RSA *rsa) SSLerr(SSL_F_SSL_CTX_USE_RSAPRIVATEKEY,ERR_R_PASSED_NULL_PARAMETER); return(0); } - if (!ssl_cert_instantiate(&ctx->default_cert, NULL)) + if (!ssl_cert_inst(&ctx->cert)) { SSLerr(SSL_F_SSL_CTX_USE_RSAPRIVATEKEY,ERR_R_MALLOC_FAILURE); return(0); @@ -582,15 +558,15 @@ int SSL_CTX_use_RSAPrivateKey(SSL_CTX *ctx, RSA *rsa) return(0); } - CRYPTO_add(&rsa->references,1,CRYPTO_LOCK_RSA); + RSA_up_ref(rsa); EVP_PKEY_assign_RSA(pkey,rsa); - ret=ssl_set_pkey(ctx->default_cert,pkey); + ret=ssl_set_pkey(ctx->cert, pkey); EVP_PKEY_free(pkey); return(ret); } -#ifndef NO_STDIO +#ifndef OPENSSL_NO_STDIO int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX *ctx, const char *file, int type) { int j,ret=0; @@ -618,7 +594,7 @@ int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX *ctx, const char *file, int type) { j=ERR_R_PEM_LIB; rsa=PEM_read_bio_RSAPrivateKey(in,NULL, - ctx->default_passwd_callback); + ctx->default_passwd_callback,ctx->default_passwd_callback_userdata); } else { @@ -638,10 +614,10 @@ end: } #endif -int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, unsigned char *d, long len) +int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, const unsigned char *d, long len) { int ret; - unsigned char *p; + const unsigned char *p; RSA *rsa; p=d; @@ -655,7 +631,7 @@ int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, unsigned char *d, long len) RSA_free(rsa); return(ret); } -#endif /* !NO_RSA */ +#endif /* !OPENSSL_NO_RSA */ int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey) { @@ -664,15 +640,15 @@ int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey) SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY,ERR_R_PASSED_NULL_PARAMETER); return(0); } - if (!ssl_cert_instantiate(&ctx->default_cert, NULL)) + if (!ssl_cert_inst(&ctx->cert)) { SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY,ERR_R_MALLOC_FAILURE); return(0); } - return(ssl_set_pkey(ctx->default_cert,pkey)); + return(ssl_set_pkey(ctx->cert,pkey)); } -#ifndef NO_STDIO +#ifndef OPENSSL_NO_STDIO int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type) { int j,ret=0; @@ -695,7 +671,12 @@ int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type) { j=ERR_R_PEM_LIB; pkey=PEM_read_bio_PrivateKey(in,NULL, - ctx->default_passwd_callback); + ctx->default_passwd_callback,ctx->default_passwd_callback_userdata); + } + else if (type == SSL_FILETYPE_ASN1) + { + j = ERR_R_ASN1_LIB; + pkey = d2i_PrivateKey_bio(in,NULL); } else { @@ -715,11 +696,11 @@ end: } #endif -int SSL_CTX_use_PrivateKey_ASN1(int type, SSL_CTX *ctx, unsigned char *d, +int SSL_CTX_use_PrivateKey_ASN1(int type, SSL_CTX *ctx, const unsigned char *d, long len) { int ret; - unsigned char *p; + const unsigned char *p; EVP_PKEY *pkey; p=d; @@ -735,7 +716,7 @@ int SSL_CTX_use_PrivateKey_ASN1(int type, SSL_CTX *ctx, unsigned char *d, } -#ifndef NO_STDIO +#ifndef OPENSSL_NO_STDIO /* Read a file that contains our certificate in "PEM" format, * possibly followed by a sequence of CA certificates that should be * sent to the peer in the Certificate message. @@ -746,7 +727,9 @@ int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file) int ret=0; X509 *x=NULL; - in=BIO_new(BIO_s_file_internal()); + ERR_clear_error(); /* clear error stack for SSL_CTX_use_certificate() */ + + in = BIO_new(BIO_s_file_internal()); if (in == NULL) { SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE,ERR_R_BUF_LIB); @@ -759,14 +742,16 @@ int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file) goto end; } - x=PEM_read_bio_X509(in,NULL,ctx->default_passwd_callback); + x=PEM_read_bio_X509_AUX(in,NULL,ctx->default_passwd_callback, + ctx->default_passwd_callback_userdata); if (x == NULL) { SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE,ERR_R_PEM_LIB); goto end; } - ret=SSL_CTX_use_certificate(ctx,x); + ret = SSL_CTX_use_certificate(ctx, x); + if (ERR_peek_error() != 0) ret = 0; /* Key/certificate mismatch doesn't imply ret==0 ... */ if (ret) @@ -778,13 +763,15 @@ int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file) int r; unsigned long err; - if (ctx->extra_certs != NULL) + if (ctx->extra_certs != NULL) { sk_X509_pop_free(ctx->extra_certs, X509_free); ctx->extra_certs = NULL; } - while ((ca = PEM_read_bio_X509(in,NULL,ctx->default_passwd_callback)) + while ((ca = PEM_read_bio_X509(in, NULL, + ctx->default_passwd_callback, + ctx->default_passwd_callback_userdata)) != NULL) { r = SSL_CTX_add_extra_chain_cert(ctx, ca); @@ -794,15 +781,15 @@ int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file) ret = 0; goto end; } - /* Note that we must not free r if it was succesully + /* Note that we must not free r if it was successfully * added to the chain (while we must free the main * certificate, since its reference count is increased * by SSL_CTX_use_certificate). */ } /* When the while loop ends, it's usually just EOF. */ - err = ERR_peek_error(); + err = ERR_peek_last_error(); if (ERR_GET_LIB(err) == ERR_LIB_PEM && ERR_GET_REASON(err) == PEM_R_NO_START_LINE) - (void) ERR_get_error(); + ERR_clear_error(); else ret = 0; /* some real error */ } @@ -813,3 +800,478 @@ end: return(ret); } #endif + +#ifndef OPENSSL_NO_TLSEXT +/* authz_validate returns true iff authz is well formed, i.e. that it meets the + * wire format as documented in the CERT_PKEY structure and that there are no + * duplicate entries. */ +static char authz_validate(const unsigned char *authz, size_t length) + { + unsigned char types_seen_bitmap[32]; + + if (!authz) + return 1; + + memset(types_seen_bitmap, 0, sizeof(types_seen_bitmap)); + + for (;;) + { + unsigned char type, byte, bit; + unsigned short len; + + if (!length) + return 1; + + type = *(authz++); + length--; + + byte = type / 8; + bit = type & 7; + if (types_seen_bitmap[byte] & (1 << bit)) + return 0; + types_seen_bitmap[byte] |= (1 << bit); + + if (length < 2) + return 0; + len = ((unsigned short) authz[0]) << 8 | + ((unsigned short) authz[1]); + authz += 2; + length -= 2; + + if (length < len) + return 0; + + authz += len; + length -= len; + } + } + +static int serverinfo_find_extension(const unsigned char *serverinfo, + size_t serverinfo_length, + unsigned short extension_type, + const unsigned char **extension_data, + unsigned short *extension_length) + { + *extension_data = NULL; + *extension_length = 0; + if (serverinfo == NULL || serverinfo_length == 0) + return 0; + for (;;) + { + unsigned short type = 0; /* uint16 */ + unsigned short len = 0; /* uint16 */ + + /* end of serverinfo */ + if (serverinfo_length == 0) + return -1; /* Extension not found */ + + /* read 2-byte type field */ + if (serverinfo_length < 2) + return 0; /* Error */ + type = (serverinfo[0] << 8) + serverinfo[1]; + serverinfo += 2; + serverinfo_length -= 2; + + /* read 2-byte len field */ + if (serverinfo_length < 2) + return 0; /* Error */ + len = (serverinfo[0] << 8) + serverinfo[1]; + serverinfo += 2; + serverinfo_length -= 2; + + if (len > serverinfo_length) + return 0; /* Error */ + + if (type == extension_type) + { + *extension_data = serverinfo; + *extension_length = len; + return 1; /* Success */ + } + + serverinfo += len; + serverinfo_length -= len; + } + return 0; /* Error */ + } + +static int serverinfo_srv_first_cb(SSL *s, unsigned short ext_type, + const unsigned char *in, + unsigned short inlen, int *al, + void *arg) + { + if (inlen != 0) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + return 1; + } + +static int serverinfo_srv_second_cb(SSL *s, unsigned short ext_type, + const unsigned char **out, unsigned short *outlen, + void *arg) + { + const unsigned char *serverinfo = NULL; + size_t serverinfo_length = 0; + + /* Is there serverinfo data for the chosen server cert? */ + if ((ssl_get_server_cert_serverinfo(s, &serverinfo, + &serverinfo_length)) != 0) + { + /* Find the relevant extension from the serverinfo */ + int retval = serverinfo_find_extension(serverinfo, serverinfo_length, + ext_type, out, outlen); + if (retval == 0) + return 0; /* Error */ + if (retval == -1) + return -1; /* No extension found, don't send extension */ + return 1; /* Send extension */ + } + return -1; /* No serverinfo data found, don't send extension */ + } + +/* With a NULL context, this function just checks that the serverinfo data + parses correctly. With a non-NULL context, it registers callbacks for + the included extensions. */ +static int serverinfo_process_buffer(const unsigned char *serverinfo, + size_t serverinfo_length, SSL_CTX *ctx) + { + if (serverinfo == NULL || serverinfo_length == 0) + return 0; + for (;;) + { + unsigned short ext_type = 0; /* uint16 */ + unsigned short len = 0; /* uint16 */ + + /* end of serverinfo */ + if (serverinfo_length == 0) + return 1; + + /* read 2-byte type field */ + if (serverinfo_length < 2) + return 0; + /* FIXME: check for types we understand explicitly? */ + + /* Register callbacks for extensions */ + ext_type = (serverinfo[0] << 8) + serverinfo[1]; + if (ctx && !SSL_CTX_set_custom_srv_ext(ctx, ext_type, + serverinfo_srv_first_cb, + serverinfo_srv_second_cb, NULL)) + return 0; + + serverinfo += 2; + serverinfo_length -= 2; + + /* read 2-byte len field */ + if (serverinfo_length < 2) + return 0; + len = (serverinfo[0] << 8) + serverinfo[1]; + serverinfo += 2; + serverinfo_length -= 2; + + if (len > serverinfo_length) + return 0; + + serverinfo += len; + serverinfo_length -= len; + } + } + +static const unsigned char *authz_find_data(const unsigned char *authz, + size_t authz_length, + unsigned char data_type, + size_t *data_length) + { + if (authz == NULL) return NULL; + if (!authz_validate(authz, authz_length)) + { + SSLerr(SSL_F_AUTHZ_FIND_DATA,SSL_R_INVALID_AUTHZ_DATA); + return NULL; + } + + for (;;) + { + unsigned char type; + unsigned short len; + if (!authz_length) + return NULL; + + type = *(authz++); + authz_length--; + + /* We've validated the authz data, so we don't have to + * check again that we have enough bytes left. */ + len = ((unsigned short) authz[0]) << 8 | + ((unsigned short) authz[1]); + authz += 2; + authz_length -= 2; + if (type == data_type) + { + *data_length = len; + return authz; + } + authz += len; + authz_length -= len; + } + /* No match */ + return NULL; + } + +static int ssl_set_authz(CERT *c, unsigned char *authz, size_t authz_length) + { + CERT_PKEY *current_key = c->key; + if (current_key == NULL) + return 0; + if (!authz_validate(authz, authz_length)) + { + SSLerr(SSL_F_SSL_SET_AUTHZ,SSL_R_INVALID_AUTHZ_DATA); + return(0); + } + current_key->authz = OPENSSL_realloc(current_key->authz, authz_length); + if (current_key->authz == NULL) + { + SSLerr(SSL_F_SSL_SET_AUTHZ,ERR_R_MALLOC_FAILURE); + return 0; + } + current_key->authz_length = authz_length; + memcpy(current_key->authz, authz, authz_length); + return 1; + } + +int SSL_CTX_use_authz(SSL_CTX *ctx, unsigned char *authz, + size_t authz_length) + { + if (authz == NULL) + { + SSLerr(SSL_F_SSL_CTX_USE_AUTHZ,ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + if (!ssl_cert_inst(&ctx->cert)) + { + SSLerr(SSL_F_SSL_CTX_USE_AUTHZ,ERR_R_MALLOC_FAILURE); + return 0; + } + return ssl_set_authz(ctx->cert, authz, authz_length); + } + +int SSL_CTX_use_serverinfo(SSL_CTX *ctx, const unsigned char *serverinfo, + size_t serverinfo_length) + { + if (ctx == NULL || serverinfo == NULL || serverinfo_length == 0) + { + SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO,ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + if (!serverinfo_process_buffer(serverinfo, serverinfo_length, NULL)) + { + SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO,SSL_R_INVALID_SERVERINFO_DATA); + return 0; + } + if (!ssl_cert_inst(&ctx->cert)) + { + SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO,ERR_R_MALLOC_FAILURE); + return 0; + } + if (ctx->cert->key == NULL) + { + SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO,ERR_R_INTERNAL_ERROR); + return 0; + } + ctx->cert->key->serverinfo = OPENSSL_realloc(ctx->cert->key->serverinfo, + serverinfo_length); + if (ctx->cert->key->serverinfo == NULL) + { + SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO,ERR_R_MALLOC_FAILURE); + return 0; + } + memcpy(ctx->cert->key->serverinfo, serverinfo, serverinfo_length); + ctx->cert->key->serverinfo_length = serverinfo_length; + + /* Now that the serverinfo is validated and stored, go ahead and + * register callbacks. */ + if (!serverinfo_process_buffer(serverinfo, serverinfo_length, ctx)) + { + SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO,SSL_R_INVALID_SERVERINFO_DATA); + return 0; + } + return 1; + } + +int SSL_use_authz(SSL *ssl, unsigned char *authz, size_t authz_length) + { + if (authz == NULL) + { + SSLerr(SSL_F_SSL_USE_AUTHZ,ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + if (!ssl_cert_inst(&ssl->cert)) + { + SSLerr(SSL_F_SSL_USE_AUTHZ,ERR_R_MALLOC_FAILURE); + return 0; + } + return ssl_set_authz(ssl->cert, authz, authz_length); + } + +const unsigned char *SSL_CTX_get_authz_data(SSL_CTX *ctx, unsigned char type, + size_t *data_length) + { + CERT_PKEY *current_key; + + if (ctx->cert == NULL) + return NULL; + current_key = ctx->cert->key; + if (current_key->authz == NULL) + return NULL; + return authz_find_data(current_key->authz, + current_key->authz_length, type, data_length); + } + +#ifndef OPENSSL_NO_STDIO +/* read_authz returns a newly allocated buffer with authz data */ +static unsigned char *read_authz(const char *file, size_t *authz_length) + { + BIO *authz_in = NULL; + unsigned char *authz = NULL; + /* Allow authzs up to 64KB. */ + static const size_t authz_limit = 65536; + size_t read_length; + unsigned char *ret = NULL; + + authz_in = BIO_new(BIO_s_file_internal()); + if (authz_in == NULL) + { + SSLerr(SSL_F_READ_AUTHZ,ERR_R_BUF_LIB); + goto end; + } + + if (BIO_read_filename(authz_in,file) <= 0) + { + SSLerr(SSL_F_READ_AUTHZ,ERR_R_SYS_LIB); + goto end; + } + + authz = OPENSSL_malloc(authz_limit); + read_length = BIO_read(authz_in, authz, authz_limit); + if (read_length == authz_limit || read_length <= 0) + { + SSLerr(SSL_F_READ_AUTHZ,SSL_R_AUTHZ_DATA_TOO_LARGE); + OPENSSL_free(authz); + goto end; + } + *authz_length = read_length; + ret = authz; +end: + if (authz_in != NULL) BIO_free(authz_in); + return ret; + } + +int SSL_CTX_use_authz_file(SSL_CTX *ctx, const char *file) + { + unsigned char *authz = NULL; + size_t authz_length = 0; + int ret; + + authz = read_authz(file, &authz_length); + if (authz == NULL) + return 0; + + ret = SSL_CTX_use_authz(ctx, authz, authz_length); + /* SSL_CTX_use_authz makes a local copy of the authz. */ + OPENSSL_free(authz); + return ret; + } + +int SSL_use_authz_file(SSL *ssl, const char *file) + { + unsigned char *authz = NULL; + size_t authz_length = 0; + int ret; + + authz = read_authz(file, &authz_length); + if (authz == NULL) + return 0; + + ret = SSL_use_authz(ssl, authz, authz_length); + /* SSL_use_authz makes a local copy of the authz. */ + OPENSSL_free(authz); + return ret; + } + +int SSL_CTX_use_serverinfo_file(SSL_CTX *ctx, const char *file) + { + unsigned char *serverinfo = NULL; + size_t serverinfo_length = 0; + unsigned char* extension = 0; + long extension_length = 0; + char* name = NULL; + char* header = NULL; + int ret = 0; + BIO *bin = NULL; + size_t num_extensions = 0; + + if (ctx == NULL || file == NULL) + { + SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE,ERR_R_PASSED_NULL_PARAMETER); + goto end; + } + + bin = BIO_new(BIO_s_file_internal()); + if (bin == NULL) + { + SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, ERR_R_BUF_LIB); + goto end; + } + if (BIO_read_filename(bin, file) <= 0) + { + SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, ERR_R_SYS_LIB); + goto end; + } + + for (num_extensions=0;; num_extensions++) + { + if (PEM_read_bio(bin, &name, &header, &extension, &extension_length) == 0) + { + /* There must be at least one extension in this file */ + if (num_extensions == 0) + { + SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, ERR_R_PEM_LIB); + goto end; + } + else /* End of file, we're done */ + break; + } + /* Check that the decoded PEM data is plausible (valid length field) */ + if (extension_length < 4 || (extension[2] << 8) + extension[3] != extension_length - 4) + { + SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, ERR_R_PEM_LIB); + goto end; + } + /* Append the decoded extension to the serverinfo buffer */ + serverinfo = OPENSSL_realloc(serverinfo, serverinfo_length + extension_length); + if (serverinfo == NULL) + { + SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, ERR_R_MALLOC_FAILURE); + goto end; + } + memcpy(serverinfo + serverinfo_length, extension, extension_length); + serverinfo_length += extension_length; + + OPENSSL_free(name); name = NULL; + OPENSSL_free(header); header = NULL; + OPENSSL_free(extension); extension = NULL; + } + + ret = SSL_CTX_use_serverinfo(ctx, serverinfo, serverinfo_length); +end: + /* SSL_CTX_use_serverinfo makes a local copy of the serverinfo. */ + OPENSSL_free(name); + OPENSSL_free(header); + OPENSSL_free(extension); + OPENSSL_free(serverinfo); + if (bin != NULL) + BIO_free(bin); + return ret; + } +#endif /* OPENSSL_NO_STDIO */ +#endif /* OPENSSL_NO_TLSEXT */