X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=ssl%2Fssl_rsa.c;h=6f9337e1503228253ca19ea7842b78f8b603e7ba;hp=855952d54cfb72454e3770f2d883d7b344a0a2b8;hb=0cfefe4b6dcc6947c236b0f10a7f9e2f02273075;hpb=a9e1c50bb09a110d4774e6710f9322344684fa2d diff --git a/ssl/ssl_rsa.c b/ssl/ssl_rsa.c index 855952d54c..6f9337e150 100644 --- a/ssl/ssl_rsa.c +++ b/ssl/ssl_rsa.c @@ -66,17 +66,21 @@ 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) { + int rv; if (x == NULL) { SSLerr(SSL_F_SSL_USE_CERTIFICATE,ERR_R_PASSED_NULL_PARAMETER); return(0); } + rv = ssl_security_cert(ssl, NULL, x, 0, 1); + if (rv != 1) + { + SSLerr(SSL_F_SSL_USE_CERTIFICATE, rv); + return 0; + } + if (!ssl_cert_inst(&ssl->cert)) { SSLerr(SSL_F_SSL_USE_CERTIFICATE,ERR_R_MALLOC_FAILURE); @@ -292,7 +296,7 @@ end: } #endif -int SSL_use_RSAPrivateKey_ASN1(SSL *ssl, unsigned char *d, long len) +int SSL_use_RSAPrivateKey_ASN1(SSL *ssl, const unsigned char *d, long len) { int ret; const unsigned char *p; @@ -397,11 +401,18 @@ int SSL_use_PrivateKey_ASN1(int type, SSL *ssl, const unsigned char *d, long len int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x) { + int rv; if (x == NULL) { SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE,ERR_R_PASSED_NULL_PARAMETER); return(0); } + rv = ssl_security_cert(NULL, ctx, x, 0, 1); + if (rv != 1) + { + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE, rv); + return 0; + } if (!ssl_cert_inst(&ctx->cert)) { SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE,ERR_R_MALLOC_FAILURE); @@ -463,15 +474,6 @@ static int ssl_set_cert(CERT *c, X509 *x) X509_free(c->pkeys[i].x509); CRYPTO_add(&x->references,1,CRYPTO_LOCK_X509); c->pkeys[i].x509=x; -#ifndef OPENSSL_NO_TLSEXT - /* Free the old authz data, if it exists. */ - if (c->pkeys[i].authz != NULL) - { - OPENSSL_free(c->pkeys[i].authz); - c->pkeys[i].authz = NULL; - c->pkeys[i].authz_length = 0; - } -#endif c->key= &(c->pkeys[i]); c->valid=0; @@ -771,19 +773,15 @@ int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file) X509 *ca; int r; unsigned long err; - - if (ctx->extra_certs != NULL) - { - sk_X509_pop_free(ctx->extra_certs, X509_free); - ctx->extra_certs = NULL; - } + SSL_CTX_clear_chain_certs(ctx); + 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); + r = SSL_CTX_add0_chain_cert(ctx, ca); if (!r) { X509_free(ca); @@ -811,94 +809,272 @@ end: #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) +static int serverinfo_find_extension(const unsigned char *serverinfo, + size_t serverinfo_length, + unsigned int extension_type, + const unsigned char **extension_data, + size_t *extension_length) + { + *extension_data = NULL; + *extension_length = 0; + if (serverinfo == NULL || serverinfo_length == 0) + return 0; + for (;;) + { + unsigned int type = 0; + size_t len = 0; + + /* 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_parse_cb(SSL *s, unsigned int ext_type, + const unsigned char *in, + size_t inlen, int *al, + void *arg) { - unsigned char types_seen_bitmap[32]; - if (!authz) - return 1; + if (inlen != 0) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } - memset(types_seen_bitmap, 0, sizeof(types_seen_bitmap)); + return 1; + } + +static int serverinfo_srv_add_cb(SSL *s, unsigned int ext_type, + const unsigned char **out, size_t *outlen, + int *al, 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 char type, byte, bit; - unsigned short len; + unsigned int ext_type = 0; + size_t len = 0; - if (!length) + /* end of serverinfo */ + if (serverinfo_length == 0) return 1; - type = *(authz++); - length--; - - byte = type / 8; - bit = type & 7; - if (types_seen_bitmap[byte] & (1 << bit)) + /* 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_add_server_custom_ext(ctx, ext_type, + serverinfo_srv_add_cb, + NULL, NULL, + serverinfo_srv_parse_cb, + NULL)) return 0; - types_seen_bitmap[byte] |= (1 << bit); - if (length < 2) + serverinfo += 2; + serverinfo_length -= 2; + + /* read 2-byte len field */ + if (serverinfo_length < 2) return 0; - len = ((unsigned short) authz[0]) << 8 | - ((unsigned short) authz[1]); - authz += 2; - length -= 2; + len = (serverinfo[0] << 8) + serverinfo[1]; + serverinfo += 2; + serverinfo_length -= 2; - if (length < len) + if (len > serverinfo_length) return 0; - authz += len; - length -= len; + serverinfo += len; + serverinfo_length -= len; } } -static int ssl_set_authz(CERT *c, unsigned char *authz, size_t authz_length) +int SSL_CTX_use_serverinfo(SSL_CTX *ctx, const unsigned char *serverinfo, + size_t serverinfo_length) { - CERT_PKEY *current_key = c->key; - if (current_key == NULL) - return 0; - if (!authz_validate(authz, authz_length)) + if (ctx == NULL || serverinfo == NULL || serverinfo_length == 0) { - SSLerr(SSL_F_SSL_SET_AUTHZ,SSL_R_INVALID_AUTHZ_DATA); - return(0); + SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO,ERR_R_PASSED_NULL_PARAMETER); + return 0; } - current_key->authz = OPENSSL_realloc(current_key->authz, authz_length); - 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) + if (!serverinfo_process_buffer(serverinfo, serverinfo_length, NULL)) { - SSLerr(SSL_F_SSL_CTX_USE_AUTHZ,ERR_R_PASSED_NULL_PARAMETER); + 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_AUTHZ,ERR_R_MALLOC_FAILURE); + 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; } - return ssl_set_authz(ctx->cert, authz, authz_length); + 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) +#ifndef OPENSSL_NO_STDIO +int SSL_CTX_use_serverinfo_file(SSL_CTX *ctx, const char *file) { - if (authz == NULL) + unsigned char *serverinfo = NULL; + size_t serverinfo_length = 0; + unsigned char* extension = 0; + long extension_length = 0; + char* name = NULL; + char* header = NULL; + char namePrefix[] = "SERVERINFO FOR "; + 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_USE_AUTHZ,ERR_R_PASSED_NULL_PARAMETER); - return 0; + SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, ERR_R_BUF_LIB); + goto end; } - if (!ssl_cert_inst(&ssl->cert)) + if (BIO_read_filename(bin, file) <= 0) { - SSLerr(SSL_F_SSL_USE_AUTHZ,ERR_R_MALLOC_FAILURE); - return 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, SSL_R_NO_PEM_EXTENSIONS); + goto end; + } + else /* End of file, we're done */ + break; + } + /* Check that PEM name starts with "BEGIN SERVERINFO FOR " */ + if (strlen(name) < strlen(namePrefix)) + { + SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, SSL_R_PEM_NAME_TOO_SHORT); + goto end; + } + if (strncmp(name, namePrefix, strlen(namePrefix)) != 0) + { + SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, SSL_R_PEM_NAME_BAD_PREFIX); + goto end; + } + /* 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, SSL_R_BAD_DATA); + 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; } - return ssl_set_authz(ssl->cert, authz, authz_length); + + 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 */