From e78f7f734e236ede861d5b39e66460c8d99b3447 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Mon, 6 Dec 2021 18:44:19 +0100 Subject: [PATCH] Add Apache 2.4.51 support - Define `OPENSSL_COMPATIBLE_DEFAULTS` and `WOLFSSL_NO_OCSP_ISSUER_CHECK` for Apache config - Fix `SSL_set_timeout` to match OpenSSL signature - Implement `pkey` in `X509_INFO` - Detect attempt to connect with plain HTTP - Implement `wolfSSL_OCSP_request_add1_nonce` - Set `ssl->cipher.bits` when calling `wolfSSL_get_current_cipher` - Use custom flush method in `wolfSSL_BIO_flush` when set in BIO method - Set the TLS version options in the `ssl->options` at the end of ClientHello parsing - Don't modify the `ssl->version` when in a handshake (`ssl->msgsReceived.got_client_hello` is set) - `wolfSSL_get_shutdown` returns a full bidirectional return when the SSL object is cleared. `wolfSSL_get_shutdown` calls `wolfSSL_clear` on a successful shutdown so if we detect a cleared SSL object, assume full shutdown was performed. --- configure.ac | 2 + src/bio.c | 6 +- src/internal.c | 36 ++++- src/keys.c | 7 +- src/ocsp.c | 43 +++++- src/ssl.c | 327 +++++++++++++++++++++--------------------- tests/api.c | 105 +++++++++++++- wolfcrypt/src/asn.c | 52 +++++-- wolfcrypt/src/evp.c | 57 +++++++- wolfssl/openssl/ec.h | 3 +- wolfssl/openssl/evp.h | 10 ++ wolfssl/openssl/ssl.h | 7 +- 12 files changed, 452 insertions(+), 203 deletions(-) diff --git a/configure.ac b/configure.ac index c70dd4891..fdcb16e14 100644 --- a/configure.ac +++ b/configure.ac @@ -4850,6 +4850,8 @@ then AM_CFLAGS="$AM_CFLAGS -DHAVE_EX_DATA -DWOLFSSL_SIGNER_DER_CERT" AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_CERT_EXT -DWOLFSSL_CERT_GEN" AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_ALWAYS_KEEP_SNI" + AM_CFLAGS="$AM_CFLAGS -DOPENSSL_COMPATIBLE_DEFAULTS" + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_OCSP_ISSUER_CHECK" # Requires OCSP make sure on if test "x$ENABLED_OCSP" = "xno" diff --git a/src/bio.c b/src/bio.c index 3d748d0b4..9df026e6d 100644 --- a/src/bio.c +++ b/src/bio.c @@ -1895,7 +1895,11 @@ int wolfSSL_BIO_flush(WOLFSSL_BIO* bio) if (bio == NULL) return WOLFSSL_FAILURE; - if (bio->type == WOLFSSL_BIO_FILE) { + if (bio->method != NULL && bio->method->ctrlCb != NULL) { + WOLFSSL_MSG("Calling custom BIO flush callback"); + return (int)bio->method->ctrlCb(bio, BIO_CTRL_FLUSH, 0, NULL); + } + else if (bio->type == WOLFSSL_BIO_FILE) { #if !defined(NO_FILESYSTEM) && defined(XFFLUSH) if (XFFLUSH((FILE *)bio->ptr) != 0) return WOLFSSL_FAILURE; diff --git a/src/internal.c b/src/internal.c index 067f720bd..c2d4416cf 100644 --- a/src/internal.c +++ b/src/internal.c @@ -5876,7 +5876,11 @@ int SetSSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup) ret = WOLFSSL_SUCCESS; /* set default ret */ ssl->ctx = ctx; /* only for passing to calls, options could change */ - ssl->version = ctx->method->version; + /* Don't change version on a SSL object that has already started a + * handshake */ + if (!ssl->msgsReceived.got_client_hello && + !ssl->msgsReceived.got_server_hello) + ssl->version = ctx->method->version; #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) ssl->options.mask = ctx->mask; ssl->options.minProto = ctx->minProto; @@ -9341,6 +9345,9 @@ int CheckAvailableSize(WOLFSSL *ssl, int size) static int GetRecordHeader(WOLFSSL* ssl, const byte* input, word32* inOutIdx, RecordLayerHeader* rh, word16 *size) { +#ifdef OPENSSL_ALL + word32 start = *inOutIdx; +#endif if (!ssl->options.dtls) { #ifdef HAVE_FUZZER if (ssl->fuzzerCb) @@ -9451,6 +9458,22 @@ static int GetRecordHeader(WOLFSSL* ssl, const byte* input, word32* inOutIdx, break; case no_type: default: +#ifdef OPENSSL_ALL + { + char *method = (char*)input + start; + /* Attempt to identify if this is a plain HTTP request. + * No size checks because this function assumes at least + * RECORD_HEADER_SZ size of data has been read which is + * also the longest string comparison in this if. */ + if (XSTRNCMP(method, "GET ", XSTR_SIZEOF("GET ")) == 0 || + XSTRNCMP(method, "POST ", XSTR_SIZEOF("POST ")) == 0 || + XSTRNCMP(method, "HEAD ", XSTR_SIZEOF("HEAD ")) == 0 || + XSTRNCMP(method, "PUT ", XSTR_SIZEOF("PUT ")) == 0) { + WOLFSSL_MSG("Plain HTTP request detected"); + return SSL_R_HTTP_REQUEST; + } + } +#endif WOLFSSL_MSG("Unknown Record Type"); return UNKNOWN_RECORD_TYPE; } @@ -12443,9 +12466,12 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx, } #endif /* SESSION_CERTS && WOLFSSL_ALT_CERT_CHAINS */ + #ifndef OPENSSL_COMPATIBLE_DEFAULTS /* Check peer's certificate version number. TLS 1.2 / 1.3 * requires the clients certificate be version 3 unless a - * different version has been negotiated using RFC 7250 */ + * different version has been negotiated using RFC 7250. + * OpenSSL doesn't appear to be performing this check. + * For TLS 1.3 see RFC8446 Section 4.4.2.3 */ if (ssl->options.side == WOLFSSL_SERVER_END) { if (args->dCert->version != WOLFSSL_X509_V3) { WOLFSSL_MSG("Peers certificate was not version 3!"); @@ -12454,6 +12480,7 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx, * giving the user a chance to override */ } } + #endif /* check if fatal error */ if (args->verifyErr) { @@ -30021,8 +30048,6 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, if (ret == 0 && ssl->options.dtls) DtlsMsgPoolReset(ssl); #endif - WOLFSSL_LEAVE("DoClientHello", ret); - WOLFSSL_END(WC_FUNC_CLIENT_HELLO_DO); out: @@ -30035,6 +30060,9 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, ret = CertSetupCbWrapper(ssl); #endif + WOLFSSL_LEAVE("DoClientHello", ret); + WOLFSSL_END(WC_FUNC_CLIENT_HELLO_DO); + return ret; } diff --git a/src/keys.c b/src/keys.c index f162af097..95d75a06b 100644 --- a/src/keys.c +++ b/src/keys.c @@ -2102,7 +2102,8 @@ int SetCipherSpecs(WOLFSSL* ssl) } /* if ECC / Normal suites else */ /* set TLS if it hasn't been turned off */ - if (ssl->version.major == 3 && ssl->version.minor >= 1) { + if (ssl->version.major == SSLv3_MAJOR && + ssl->version.minor >= TLSv1_MINOR) { #ifndef NO_TLS ssl->options.tls = 1; #if !defined(WOLFSSL_NO_TLS12) && !defined(WOLFSSL_AEAD_ONLY) @@ -2112,9 +2113,9 @@ int SetCipherSpecs(WOLFSSL* ssl) ssl->hmac = Renesas_cmn_TLS_hmac; #endif #endif - if (ssl->version.minor >= 2) { + if (ssl->version.minor >= TLSv1_1_MINOR) { ssl->options.tls1_1 = 1; - if (ssl->version.minor >= 4) + if (ssl->version.minor >= TLSv1_3_MINOR) ssl->options.tls1_3 = 1; } #endif diff --git a/src/ocsp.c b/src/ocsp.c index b7a2d9c15..283eb03a8 100644 --- a/src/ocsp.c +++ b/src/ocsp.c @@ -1217,17 +1217,46 @@ int wolfSSL_OCSP_id_get0_info(WOLFSSL_ASN1_STRING **name, return 1; } -#ifndef NO_WOLFSSL_STUB int wolfSSL_OCSP_request_add1_nonce(OcspRequest* req, unsigned char* val, int sz) { - WOLFSSL_STUB("wolfSSL_OCSP_request_add1_nonce"); - (void)req; - (void)val; - (void)sz; - return WOLFSSL_FATAL_ERROR; -} + WC_RNG rng; + + WOLFSSL_ENTER("wolfSSL_OCSP_request_add1_nonce"); + + if (req == NULL || sz > MAX_OCSP_NONCE_SZ) { + WOLFSSL_MSG("Bad parameter"); + return WOLFSSL_FAILURE; + } + + if (sz <= 0) + sz = MAX_OCSP_NONCE_SZ; + + if (val != NULL) { + XMEMCPY(req->nonce, val, sz); + } + else { + if ( +#ifndef HAVE_FIPS + wc_InitRng_ex(&rng, req->heap, INVALID_DEVID) +#else + wc_InitRng(&rng) #endif + != 0) { + WOLFSSL_MSG("RNG init failed"); + return WOLFSSL_FAILURE; + } + if (wc_RNG_GenerateBlock(&rng, req->nonce, sz) != 0) { + WOLFSSL_MSG("wc_RNG_GenerateBlock failed"); + wc_FreeRng(&rng); + return WOLFSSL_FAILURE; + } + wc_FreeRng(&rng); + } + req->nonceSz = sz; + + return WOLFSSL_SUCCESS; +} /* Returns result of OCSP nonce comparison. Return values: * 1 - nonces are both present and equal diff --git a/src/ssl.c b/src/ssl.c index 6ea2c1355..b9cfca03c 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -77,6 +77,7 @@ #ifdef OPENSSL_EXTRA /* openssl headers begin */ + #include #include #ifndef WOLFCRYPT_ONLY #include @@ -19745,6 +19746,7 @@ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out, ssl->options.isClosed = 0; ssl->options.connReset = 0; ssl->options.sentNotify = 0; + ssl->options.closeNotify = 0; ssl->options.sendVerify = 0; ssl->options.serverState = NULL_STATE; ssl->options.clientState = NULL_STATE; @@ -23000,10 +23002,24 @@ int wolfSSL_get_shutdown(const WOLFSSL* ssl) WOLFSSL_ENTER("wolfSSL_get_shutdown"); if (ssl) { - /* in OpenSSL, WOLFSSL_SENT_SHUTDOWN = 1, when closeNotifySent * - * WOLFSSL_RECEIVED_SHUTDOWN = 2, from close notify or fatal err */ - isShutdown = ((ssl->options.closeNotify||ssl->options.connReset) << 1) - | (ssl->options.sentNotify); +#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) + if (ssl->options.handShakeState == NULL_STATE) { + /* The SSL object was possibly cleared with wolfSSL_clear after + * a successful shutdown. Simulate a response for a full + * bidirectional shutdown. */ + isShutdown = WOLFSSL_SENT_SHUTDOWN | WOLFSSL_RECEIVED_SHUTDOWN; + } + else +#endif + { + /* in OpenSSL, WOLFSSL_SENT_SHUTDOWN = 1, when closeNotifySent * + * WOLFSSL_RECEIVED_SHUTDOWN = 2, from close notify or fatal err */ + if (ssl->options.sentNotify) + isShutdown |= WOLFSSL_SENT_SHUTDOWN; + if (ssl->options.closeNotify||ssl->options.connReset) + isShutdown |= WOLFSSL_RECEIVED_SHUTDOWN; + } + } return isShutdown; } @@ -23311,6 +23327,9 @@ WOLFSSL_CIPHER* wolfSSL_get_current_cipher(WOLFSSL* ssl) if (ssl) { ssl->cipher.cipherSuite0 = ssl->options.cipherSuite0; ssl->cipher.cipherSuite = ssl->options.cipherSuite; +#if defined(OPENSSL_ALL) || defined(WOLFSSL_QT) + ssl->cipher.bits = ssl->specs.key_size * 8; +#endif return &ssl->cipher; } else @@ -27976,6 +27995,8 @@ int wolfSSL_ERR_GET_LIB(unsigned long err) value = (err & 0xFFFFFFL); switch (value) { + case -SSL_R_HTTP_REQUEST: + return ERR_LIB_SSL; case PEM_R_NO_START_LINE: case PEM_R_PROBLEMS_GETTING_PASSWORD: case PEM_R_BAD_PASSWORD_READ: @@ -28010,6 +28031,8 @@ int wolfSSL_ERR_GET_REASON(unsigned long err) /* Nginx looks for this error to know to stop parsing certificates. */ if (err == ((ERR_LIB_PEM << 24) | PEM_R_NO_START_LINE)) return PEM_R_NO_START_LINE; + if (err == ((ERR_LIB_SSL << 24) | -SSL_R_HTTP_REQUEST)) + return SSL_R_HTTP_REQUEST; #endif #if defined(OPENSSL_ALL) && defined(WOLFSSL_PYTHON) if (err == ((ERR_LIB_ASN1 << 24) | ASN1_R_HEADER_TOO_LONG)) @@ -44305,23 +44328,6 @@ err: } return ret; } - - - /* sets the values of X509_PKEY based on certificate passed in - * return WOLFSSL_SUCCESS on success */ - static int wolfSSL_X509_PKEY_set(WOLFSSL_X509_PKEY* xPkey, - WOLFSSL_X509* x509) - { - if (xPkey == NULL || x509 == NULL) { - return BAD_FUNC_ARG; - } - wolfSSL_EVP_PKEY_free(xPkey->dec_pkey); - xPkey->dec_pkey = wolfSSL_X509_get_pubkey(x509); - if (xPkey->dec_pkey == NULL) { - return WOLFSSL_FAILURE; - } - return WOLFSSL_SUCCESS; - } #endif /* !NO_BIO */ @@ -44337,47 +44343,9 @@ err: #ifndef NO_BIO - /* Takes control of x509 on success - * helper function to break out code needed to set WOLFSSL_X509_INFO up - * free's "info" passed in if is not defaults - * - * returns WOLFSSL_SUCCESS on success - */ - static int wolfSSL_X509_INFO_set(WOLFSSL_X509_INFO** info, - WOLFSSL_X509* x509) - { - if (info == NULL || x509 == NULL) { - return BAD_FUNC_ARG; - } - - if (*info == NULL) { - return BAD_FUNC_ARG; - } - - /* check is fresh "info" passed in, if not free it */ - if ((*info)->x509 != NULL || (*info)->x_pkey != NULL) { - WOLFSSL_X509_INFO* tmp; - - tmp = wolfSSL_X509_INFO_new(); - if (tmp == NULL) { - WOLFSSL_MSG("Unable to create new structure"); - return MEMORY_E; - } - wolfSSL_X509_INFO_free(*info); - (*info) = tmp; - } - - (*info)->x509 = x509; - - /* @TODO info->num */ - /* @TODO info->enc_cipher */ - /* @TODO info->enc_len */ - /* @TODO info->enc_data */ - /* @TODO info->crl */ - - (*info)->x_pkey = wolfSSL_X509_PKEY_new(x509->heap); - return wolfSSL_X509_PKEY_set((*info)->x_pkey, x509); - } +#define PEM_COMPARE_HEADER(start, end, header) \ + end - start == XSTR_SIZEOF(header) && XMEMCMP(start, header, \ + XSTR_SIZEOF(header)) == 0 /** * This read one structure from bio and returns the read structure @@ -44405,8 +44373,7 @@ err: #ifdef HAVE_CRL DerBuffer* der = NULL; #endif - - (void)cb; + WOLFSSL_BIO* pemBio = NULL; if (!bio || !x509 || *x509 || !crl || *crl || !x_pkey || *x_pkey) { WOLFSSL_MSG("Bad input parameter or output parameters " @@ -44428,6 +44395,7 @@ err: if (wolfSSL_BIO_read(bio, &pem[0], pem_struct_min_sz) != pem_struct_min_sz) { + WOLFSSL_ERROR(ASN_NO_PEM_HEADER); goto err; } @@ -44487,10 +44455,8 @@ err: goto err; } else { - if (headerEnd - header == - XSTR_SIZEOF("-----BEGIN CERTIFICATE-----") && - XMEMCMP(header, "-----BEGIN CERTIFICATE-----", - XSTR_SIZEOF("-----BEGIN CERTIFICATE-----")) == 0) { + if (PEM_COMPARE_HEADER(header, headerEnd, + "-----BEGIN CERTIFICATE-----")) { /* We have a certificate */ WOLFSSL_MSG("Parsing x509 cert"); *x509 = wolfSSL_X509_load_certificate_buffer( @@ -44502,10 +44468,8 @@ err: } } #ifdef HAVE_CRL - else if (headerEnd - header == - XSTR_SIZEOF("-----BEGIN X509 CRL-----") && - XMEMCMP(header, "-----BEGIN X509 CRL-----", - XSTR_SIZEOF("-----BEGIN X509 CRL-----")) == 0) { + else if (PEM_COMPARE_HEADER(header, headerEnd, + "-----BEGIN X509 CRL-----")) { /* We have a crl */ WOLFSSL_MSG("Parsing crl"); if((PemToDer((const unsigned char*) header, footerEnd - header, @@ -44521,9 +44485,31 @@ err: } #endif else { - /* TODO support WOLFSSL_X509_PKEY as well */ - WOLFSSL_MSG("Unsupported PEM structure"); - goto err; + WOLFSSL_MSG("Parsing x509 key"); + + if (!(*x_pkey = wolfSSL_X509_PKEY_new(NULL))) { + WOLFSSL_MSG("wolfSSL_X509_PKEY_new error"); + goto err; + } + + if (!(pemBio = wolfSSL_BIO_new(wolfSSL_BIO_s_mem()))) { + WOLFSSL_MSG("wolfSSL_BIO_new error"); + goto err; + } + + if (wolfSSL_BIO_write(pemBio, header, + (int)(footerEnd - header)) != footerEnd - header) { + WOLFSSL_MSG("wolfSSL_BIO_new error"); + goto err; + } + + if (wolfSSL_PEM_read_bio_PrivateKey(pemBio, + &(*x_pkey)->dec_pkey, cb, NULL) == NULL) { + WOLFSSL_MSG("wolfSSL_PEM_read_bio_PrivateKey error"); + goto err; + } + + wolfSSL_BIO_free(pemBio); } } @@ -44540,6 +44526,12 @@ err: if (der) FreeDer(&der); #endif + if (*x_pkey) { + wolfSSL_X509_PKEY_free(*x_pkey); + *x_pkey = NULL; + } + if (pemBio) + wolfSSL_BIO_free(pemBio); return WOLFSSL_FAILURE; #endif /* WOLFSSL_PEM_TO_DER || WOLFSSL_DER_TO_PEM */ } @@ -44573,75 +44565,107 @@ err: { WOLF_STACK_OF(WOLFSSL_X509_INFO)* localSk = NULL; int ret = WOLFSSL_SUCCESS; + WOLFSSL_X509_INFO* current = NULL; + WOLFSSL_X509* x509 = NULL; + WOLFSSL_X509_CRL* crl = NULL; + WOLFSSL_X509_PKEY* x_pkey = NULL; (void)u; WOLFSSL_ENTER("wolfSSL_PEM_X509_INFO_read_bio"); + /* attempt to use passed in stack or create a new one */ + if (sk != NULL) { + localSk = sk; + } + else { + localSk = wolfSSL_sk_X509_INFO_new_null(); + } + if (localSk == NULL) { + WOLFSSL_LEAVE("wolfSSL_PEM_X509_INFO_read_bio", + MEMORY_E); + return NULL; + } + /* parse through BIO and push new info's found onto stack */ while (1) { - WOLFSSL_X509 *x509 = NULL; - WOLFSSL_X509_CRL *crl = NULL; - WOLFSSL_X509_PKEY *x_pkey = NULL; + x509 = NULL; + crl = NULL; + x_pkey = NULL; if (wolfSSL_PEM_X509_X509_CRL_X509_PKEY_read_bio(bio, cb, &x509, &crl, &x_pkey) == WOLFSSL_SUCCESS) { - WOLFSSL_X509_INFO* current; - - current = wolfSSL_X509_INFO_new(); - if (current == NULL) { - WOLFSSL_LEAVE("wolfSSL_PEM_X509_INFO_read_bio", MEMORY_E); - wolfSSL_sk_pop_free(localSk, NULL); - return NULL; + if (current == NULL || + (x509 && current->x509) || + (crl && current->crl) || + (x_pkey && current->x_pkey)) { + /* Need to create new current since existing one already + * has the member filled or this is the first successful + * read. */ + current = wolfSSL_X509_INFO_new(); + if (current == NULL) { + ret = MEMORY_E; + break; + } + if (wolfSSL_sk_X509_INFO_push(localSk, current) != + WOLFSSL_SUCCESS) { + wolfSSL_X509_INFO_free(current); + current = NULL; + ret = WOLFSSL_FAILURE; + break; + } } + if (x509) { - ret = wolfSSL_X509_INFO_set(¤t, x509); + current->x509 = x509; } else if (crl) { current->crl = crl; - ret = WOLFSSL_SUCCESS; } else if (x_pkey) { current->x_pkey = x_pkey; - ret = WOLFSSL_SUCCESS; } else { WOLFSSL_MSG("No output parameters set"); - WOLFSSL_LEAVE("wolfSSL_PEM_X509_INFO_read_bio", WOLFSSL_FAILURE); - wolfSSL_sk_pop_free(localSk, NULL); - wolfSSL_X509_INFO_free(current); - return NULL; - } - if (ret != WOLFSSL_SUCCESS) { - wolfSSL_X509_free(x509); -#ifdef HAVE_CRL - wolfSSL_X509_CRL_free(crl); -#endif - wolfSSL_X509_PKEY_free(x_pkey); - } - else { - if (!localSk) { - /* attempt to used passed in stack - * or create a new one */ - if (sk != NULL) { - localSk = sk; - } - else { - localSk = wolfSSL_sk_X509_INFO_new_null(); - } - if (localSk == NULL) { - WOLFSSL_LEAVE("wolfSSL_PEM_X509_INFO_read_bio", - MEMORY_E); - return NULL; - } - } - wolfSSL_sk_X509_INFO_push(localSk, current); + ret = WOLFSSL_FAILURE; + break; } } else { + int err = (int)wolfSSL_ERR_peek_last_error(); + if (ERR_GET_LIB(err) == ERR_LIB_PEM && + ERR_GET_REASON(err) == PEM_R_NO_START_LINE) { + /* + * wolfSSL_PEM_X509_X509_CRL_X509_PKEY_read_bio pushes an + * ASN_NO_PEM_HEADER error to the error queue on file end. + * This should not be left for the caller to find so we + * clear the last error. This also indicates that nothing + * more was found in the BIO. + */ + wc_RemoveErrorNode(-1); + } + else { + ret = WOLFSSL_FAILURE; + } break; } } + if (ret != WOLFSSL_SUCCESS || + wolfSSL_sk_X509_INFO_num(localSk) == 0) { + /* current should always be pushed onto the localsk stack at this + * point. The only case when it isn't is when + * wolfSSL_sk_X509_INFO_push fails but in that case the current + * free is handled inside the loop. */ + if (localSk != sk) { + wolfSSL_sk_pop_free(localSk, NULL); + } + wolfSSL_X509_free(x509); +#ifdef HAVE_CRL + wolfSSL_X509_CRL_free(crl); +#endif + wolfSSL_X509_PKEY_free(x_pkey); + localSk = NULL; + } WOLFSSL_LEAVE("wolfSSL_PEM_X509_INFO_read_bio", ret); return localSk; } @@ -47726,24 +47750,19 @@ int wolfSSL_sk_X509_INFO_num(const WOLF_STACK_OF(WOLFSSL_X509_INFO) *sk) { WOLFSSL_ENTER("wolfSSL_sk_X509_INFO_num"); - if (sk == NULL) - return -1; - return (int)sk->num; + return wolfSSL_sk_num(sk); } -WOLFSSL_X509_INFO* wolfSSL_sk_X509_INFO_value(const WOLF_STACK_OF(WOLFSSL_X509_INFO) *sk, int i) +WOLFSSL_X509_INFO* wolfSSL_sk_X509_INFO_value( + const WOLF_STACK_OF(WOLFSSL_X509_INFO) *sk, int i) { WOLFSSL_ENTER("wolfSSL_sk_X509_INFO_value"); - for (; sk != NULL && i > 0; i--) - sk = sk->next; - - if (i != 0 || sk == NULL) - return NULL; - return sk->data.info; + return wolfSSL_sk_value(sk, i); } -WOLFSSL_X509_INFO* wolfSSL_sk_X509_INFO_pop(WOLF_STACK_OF(WOLFSSL_X509_INFO)* sk) +WOLFSSL_X509_INFO* wolfSSL_sk_X509_INFO_pop( + WOLF_STACK_OF(WOLFSSL_X509_INFO)* sk) { WOLFSSL_STACK* node; WOLFSSL_X509_INFO* info; @@ -47793,37 +47812,7 @@ void wolfSSL_sk_X509_INFO_free(WOLF_STACK_OF(WOLFSSL_X509_INFO) *sk) int wolfSSL_sk_X509_INFO_push(WOLF_STACK_OF(WOLFSSL_X509_INFO)* sk, WOLFSSL_X509_INFO* in) { - WOLFSSL_STACK* node; - - if (sk == NULL || in == NULL) { - return WOLFSSL_FAILURE; - } - - /* no previous values in stack */ - if (sk->data.info == NULL) { - sk->data.info = in; - sk->num += 1; - return WOLFSSL_SUCCESS; - } - - /* stack already has value(s) create a new node and add more */ - node = (WOLFSSL_STACK*)XMALLOC(sizeof(WOLFSSL_STACK), NULL, - DYNAMIC_TYPE_X509); - if (node == NULL) { - WOLFSSL_MSG("Memory error"); - return WOLFSSL_FAILURE; - } - XMEMSET(node, 0, sizeof(WOLFSSL_STACK)); - - /* push new obj onto head of stack */ - node->data.info = sk->data.info; - node->next = sk->next; - node->type = sk->type; - sk->next = node; - sk->data.info = in; - sk->num += 1; - - return WOLFSSL_SUCCESS; + return wolfSSL_sk_push(sk, in); } /* Creates a duplicate of WOLF_STACK_OF(WOLFSSL_X509_NAME). @@ -49391,6 +49380,11 @@ unsigned long wolfSSL_ERR_peek_error_line_data(const char **file, int *line, if (ret == -ASN_NO_PEM_HEADER) return (ERR_LIB_PEM << 24) | PEM_R_NO_START_LINE; + #ifdef OPENSSL_ALL + /* PARSE_ERROR is returned if an HTTP request is detected. */ + if (ret == -SSL_R_HTTP_REQUEST) + return (ERR_LIB_SSL << 24) | -SSL_R_HTTP_REQUEST; + #endif #if defined(OPENSSL_ALL) && defined(WOLFSSL_PYTHON) if (ret == ASN1_R_HEADER_TOO_LONG) { return (ERR_LIB_ASN1 << 24) | ASN1_R_HEADER_TOO_LONG; @@ -59431,21 +59425,20 @@ void wolfSSL_BIO_set_init(WOLFSSL_BIO* bio, int init) (void)bio; (void)init; } +#endif /* NO_WOLFSSL_STUB */ void wolfSSL_BIO_set_shutdown(WOLFSSL_BIO* bio, int shut) { - WOLFSSL_STUB("wolfSSL_BIO_set_shutdown"); - (void)bio; - (void)shut; - + WOLFSSL_ENTER("wolfSSL_BIO_set_shutdown"); + if (bio != NULL) + bio->shutdown = shut; } + int wolfSSL_BIO_get_shutdown(WOLFSSL_BIO* bio) { - WOLFSSL_STUB("wolfSSL_BIO_get_shutdown"); - (void)bio; - return 0; + WOLFSSL_ENTER("wolfSSL_BIO_get_shutdown"); + return bio != NULL && bio->shutdown; } -#endif /* NO_WOLFSSL_STUB */ void wolfSSL_BIO_clear_retry_flags(WOLFSSL_BIO* bio) { diff --git a/tests/api.c b/tests/api.c index b2d327ce5..db5594508 100644 --- a/tests/api.c +++ b/tests/api.c @@ -8825,7 +8825,11 @@ static void test_set_x509_badversion(WOLFSSL_CTX* ctx) /* override certificate version error */ static int test_override_x509(int preverify, WOLFSSL_X509_STORE_CTX* store) { +#ifndef OPENSSL_COMPATIBLE_DEFAULTS AssertIntEQ(store->error, ASN_VERSION_E); +#else + AssertIntEQ(store->error, 0); +#endif AssertIntEQ((int)wolfSSL_X509_get_version(store->current_cert), 1); (void)preverify; return 1; @@ -8897,8 +8901,13 @@ static void test_wolfSSL_X509_TLS_version(void) test_client_nofail(&client_args, NULL); join_thread(serverThread); +#ifndef OPENSSL_COMPATIBLE_DEFAULTS AssertIntEQ(client_args.return_code, TEST_FAIL); AssertIntEQ(server_args.return_code, TEST_FAIL); +#else + AssertIntEQ(client_args.return_code, TEST_SUCCESS); + AssertIntEQ(server_args.return_code, TEST_SUCCESS); +#endif FreeTcpReady(&ready); @@ -29744,6 +29753,68 @@ static void test_wolfSSL_X509_NAME_hash(void) #endif } +#ifndef NO_BIO +static void test_wolfSSL_X509_INFO_multiple_info(void) +{ +#if defined(OPENSSL_ALL) && !defined(NO_RSA) + STACK_OF(X509_INFO) *info_stack; + X509_INFO *info; + int len; + int i; + const char* files[] = { + cliCertFile, + cliKeyFile, + /* This needs to be the order as svrCertFile contains the + * intermediate cert as well. */ + svrKeyFile, + svrCertFile, + NULL, + }; + const char** curFile; + BIO *fileBIO; + BIO *concatBIO = NULL; + byte tmp[FOURK_BUF]; + + /* concatenate the cert and the key file to force PEM_X509_INFO_read_bio + * to group objects together. */ + AssertNotNull(concatBIO = BIO_new(BIO_s_mem())); + for (curFile = files; *curFile != NULL; curFile++) { + int fileLen; + AssertNotNull(fileBIO = BIO_new_file(*curFile, "rb")); + fileLen = wolfSSL_BIO_get_len(fileBIO); + while ((len = BIO_read(fileBIO, tmp, sizeof(tmp))) > 0) { + AssertIntEQ(BIO_write(concatBIO, tmp, len), len); + fileLen -= len; + } + /* Make sure we read the entire file */ + AssertIntEQ(fileLen, 0); + BIO_free(fileBIO); + } + + AssertNotNull(info_stack = PEM_X509_INFO_read_bio(concatBIO, NULL, NULL, + NULL)); + AssertIntEQ(sk_X509_INFO_num(info_stack), 3); + for (i = 0; i < sk_X509_INFO_num(info_stack); i++) { + AssertNotNull(info = sk_X509_INFO_value(info_stack, i)); + AssertNotNull(info->x509); + AssertNull(info->crl); + if (i != 0) { + AssertNotNull(info->x_pkey); + AssertIntEQ(X509_check_private_key(info->x509, + info->x_pkey->dec_pkey), 1); + } + else { + AssertNull(info->x_pkey); + } + } + + sk_X509_INFO_pop_free(info_stack, X509_INFO_free); + BIO_free(concatBIO); + +#endif +} +#endif + #ifndef NO_BIO static void test_wolfSSL_X509_INFO(void) { @@ -29779,6 +29850,7 @@ static void test_wolfSSL_X509_INFO(void) AssertNotNull(info = sk_X509_INFO_value(info_stack, i)); AssertNotNull(info->x509); AssertNull(info->crl); + AssertNull(info->x_pkey); } sk_X509_INFO_pop_free(info_stack, X509_INFO_free); BIO_free(cert); @@ -43122,6 +43194,34 @@ static void test_wolfSSL_EVP_PKEY_id(void) printf(resultFmt, passed); #endif } + +static void test_wolfSSL_EVP_PKEY_paramgen(void) +{ +#if defined(OPENSSL_ALL) && \ + !defined(NO_ECC_SECP) && \ + /* This last bit is taken from ecc.c. It is the condition that + * defines ECC256 */ \ + ((!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && \ + ECC_MIN_KEY_SZ <= 256) + EVP_PKEY_CTX* ctx; + EVP_PKEY* pkey = NULL; + + printf(testingFmt, "wolfSSL_EVP_PKEY_paramgen"); + + AssertNotNull(ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL)); + AssertIntEQ(EVP_PKEY_paramgen_init(ctx), 1); + AssertIntEQ(EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, NID_X9_62_prime256v1), 1); + AssertIntEQ(EVP_PKEY_CTX_set_ec_param_enc(ctx, OPENSSL_EC_NAMED_CURVE), 1); + AssertIntEQ(EVP_PKEY_keygen_init(ctx), 1); + AssertIntEQ(EVP_PKEY_keygen(ctx, &pkey), 1); + + EVP_PKEY_CTX_free(ctx); + EVP_PKEY_free(pkey); + + printf(resultFmt, passed); +#endif +} + static void test_wolfSSL_EVP_PKEY_keygen(void) { #if defined(OPENSSL_ALL) @@ -48675,9 +48775,6 @@ static void test_wolfSSL_PEM_X509_INFO_read_bio(void) /* using dereference to maintain testing for Apache port*/ AssertNotNull(info = sk_X509_INFO_pop(sk)); - AssertNotNull(info->x_pkey); - AssertNotNull(info->x_pkey->dec_pkey); - AssertIntEQ(EVP_PKEY_bits(info->x_pkey->dec_pkey), 2048); AssertNotNull(subject = X509_NAME_oneline(X509_get_subject_name(info->x509), 0, 0)); @@ -51928,6 +52025,7 @@ void ApiTest(void) test_wolfSSL_X509_NAME(); test_wolfSSL_X509_NAME_hash(); #ifndef NO_BIO + test_wolfSSL_X509_INFO_multiple_info(); test_wolfSSL_X509_INFO(); #endif test_wolfSSL_X509_subject_name_hash(); @@ -52181,6 +52279,7 @@ void ApiTest(void) test_wolfSSL_EVP_PKEY_assign(); test_wolfSSL_EVP_PKEY_base_id(); test_wolfSSL_EVP_PKEY_id(); + test_wolfSSL_EVP_PKEY_paramgen(); test_wolfSSL_EVP_PKEY_keygen(); test_wolfSSL_EVP_PKEY_keygen_init(); test_wolfSSL_EVP_PKEY_missing_parameters(); diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 75fde24a9..822788fa8 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -29518,43 +29518,68 @@ int OcspResponseDecode(OcspResponse* resp, void* cm, void* heap, int noVerify) WOLFSSL_ENTER("OcspResponseDecode"); /* peel the outer SEQUENCE wrapper */ - if (GetSequence(source, &idx, &length, size) < 0) + if (GetSequence(source, &idx, &length, size) < 0) { + WOLFSSL_LEAVE("OcspResponseDecode", ASN_PARSE_E); return ASN_PARSE_E; + } /* First get the responseStatus, an ENUMERATED */ - if (GetEnumerated(source, &idx, &resp->responseStatus, size) < 0) + if (GetEnumerated(source, &idx, &resp->responseStatus, size) < 0) { + WOLFSSL_LEAVE("OcspResponseDecode", ASN_PARSE_E); return ASN_PARSE_E; + } - if (resp->responseStatus != OCSP_SUCCESSFUL) + if (resp->responseStatus != OCSP_SUCCESSFUL) { + WOLFSSL_LEAVE("OcspResponseDecode", 0); return 0; + } /* Next is an EXPLICIT record called ResponseBytes, OPTIONAL */ - if (idx >= size) - return ASN_INPUT_E; - if (GetASNTag(source, &idx, &tag, size) < 0) + if (idx >= size) { + WOLFSSL_LEAVE("OcspResponseDecode", ASN_PARSE_E); return ASN_PARSE_E; - if (tag != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC)) + } + if (GetASNTag(source, &idx, &tag, size) < 0) { + WOLFSSL_LEAVE("OcspResponseDecode", ASN_PARSE_E); return ASN_PARSE_E; - if (GetLength(source, &idx, &length, size) < 0) + } + if (tag != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC)) { + WOLFSSL_LEAVE("OcspResponseDecode", ASN_PARSE_E); return ASN_PARSE_E; + } + if (GetLength(source, &idx, &length, size) < 0) { + WOLFSSL_LEAVE("OcspResponseDecode", ASN_PARSE_E); + return ASN_PARSE_E; + } /* Get the responseBytes SEQUENCE */ - if (GetSequence(source, &idx, &length, size) < 0) + if (GetSequence(source, &idx, &length, size) < 0) { + WOLFSSL_LEAVE("OcspResponseDecode", ASN_PARSE_E); return ASN_PARSE_E; + } /* Check ObjectID for the resposeBytes */ - if (GetObjectId(source, &idx, &oid, oidOcspType, size) < 0) + if (GetObjectId(source, &idx, &oid, oidOcspType, size) < 0) { + WOLFSSL_LEAVE("OcspResponseDecode", ASN_PARSE_E); return ASN_PARSE_E; - if (oid != OCSP_BASIC_OID) + } + if (oid != OCSP_BASIC_OID) { + WOLFSSL_LEAVE("OcspResponseDecode", ASN_PARSE_E); return ASN_PARSE_E; + } ret = GetOctetString(source, &idx, &length, size); - if (ret < 0) + if (ret < 0) { + WOLFSSL_LEAVE("OcspResponseDecode", ret); return ret; + } ret = DecodeBasicOcspResponse(source, &idx, resp, size, cm, heap, noVerify); - if (ret < 0) + if (ret < 0) { + WOLFSSL_LEAVE("OcspResponseDecode", ret); return ret; + } + WOLFSSL_LEAVE("OcspResponseDecode", 0); return 0; #else DECL_ASNGETDATA(dataASN, ocspResponseASN_Length); @@ -29595,6 +29620,7 @@ int OcspResponseDecode(OcspResponse* resp, void* cm, void* heap, int noVerify) } FREE_ASNGETDATA(dataASN, resp->heap); + WOLFSSL_LEAVE("OcspResponseDecode", ret); return ret; #endif /* WOLFSSL_ASN_TEMPLATE */ } diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index 9ad03bc23..72f4b1a82 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -1420,6 +1420,9 @@ WOLFSSL_EVP_PKEY_CTX *wolfSSL_EVP_PKEY_CTX_new(WOLFSSL_EVP_PKEY *pkey, WOLFSSL_E ctx->pkey = pkey; #if !defined(NO_RSA) && !defined(HAVE_USER_RSA) ctx->padding = RSA_PKCS1_PADDING; +#endif +#ifdef HAVE_ECC + ctx->curveNID = ECC_CURVE_DEF; #endif if (wolfSSL_EVP_PKEY_up_ref(pkey) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("Couldn't increase key reference count"); @@ -1920,6 +1923,49 @@ int wolfSSL_EVP_PKEY_bits(const WOLFSSL_EVP_PKEY *pkey) } +int wolfSSL_EVP_PKEY_paramgen_init(WOLFSSL_EVP_PKEY_CTX *ctx) +{ + (void)ctx; + return WOLFSSL_SUCCESS; +} + +int wolfSSL_EVP_PKEY_CTX_set_ec_paramgen_curve_nid(WOLFSSL_EVP_PKEY_CTX *ctx, + int nid) +{ + WOLFSSL_ENTER("wolfSSL_EVP_PKEY_CTX_set_ec_paramgen_curve_nid"); +#ifdef HAVE_ECC + if (ctx != NULL && ctx->pkey != NULL && ctx->pkey->type == EVP_PKEY_EC) { + ctx->curveNID = nid; + return WOLFSSL_SUCCESS; + } + else +#endif + { +#ifndef HAVE_ECC + (void)ctx; + (void)nid; + WOLFSSL_MSG("Support not compiled in"); +#else + WOLFSSL_MSG("Bad parameter"); +#endif + return WOLFSSL_FAILURE; + } +} + +/* wolfSSL only supports writing out named curves so no need to store the flag. + * In short, it is preferred to write out the name of the curve chosen instead + * of the explicit parameters. + * The difference is nicely explained and illustrated in section + * "ECDH and Named Curves" of + * https://wiki.openssl.org/index.php/Elliptic_Curve_Diffie_Hellman */ +int EVP_PKEY_CTX_set_ec_param_enc(WOLFSSL_EVP_PKEY_CTX *ctx, + int flag) +{ + (void)ctx; + (void)flag; + return WOLFSSL_SUCCESS; +} + int wolfSSL_EVP_PKEY_keygen_init(WOLFSSL_EVP_PKEY_CTX *ctx) { (void)ctx; @@ -1933,14 +1979,23 @@ int wolfSSL_EVP_PKEY_keygen(WOLFSSL_EVP_PKEY_CTX *ctx, int ownPkey = 0; WOLFSSL_EVP_PKEY* pkey; + WOLFSSL_ENTER("wolfSSL_EVP_PKEY_keygen"); + if (ctx == NULL || ppkey == NULL) { return BAD_FUNC_ARG; } pkey = *ppkey; if (pkey == NULL) { + if (ctx->pkey == NULL || + (ctx->pkey->type != EVP_PKEY_EC && + ctx->pkey->type != EVP_PKEY_RSA)) { + WOLFSSL_MSG("Key not set or key type not supported"); + return BAD_FUNC_ARG; + } ownPkey = 1; pkey = wolfSSL_EVP_PKEY_new(); + pkey->type = ctx->pkey->type; if (pkey == NULL) return ret; @@ -1962,7 +2017,7 @@ int wolfSSL_EVP_PKEY_keygen(WOLFSSL_EVP_PKEY_CTX *ctx, #endif #ifdef HAVE_ECC case EVP_PKEY_EC: - pkey->ecc = wolfSSL_EC_KEY_new(); + pkey->ecc = wolfSSL_EC_KEY_new_by_curve_name(ctx->curveNID); if (pkey->ecc) { ret = wolfSSL_EC_KEY_generate_key(pkey->ecc); if (ret == WOLFSSL_SUCCESS) { diff --git a/wolfssl/openssl/ec.h b/wolfssl/openssl/ec.h index 253f808d2..73af2525d 100644 --- a/wolfssl/openssl/ec.h +++ b/wolfssl/openssl/ec.h @@ -76,7 +76,8 @@ enum { NID_ED25519 = ED25519k, #endif - OPENSSL_EC_NAMED_CURVE = 0x001 + OPENSSL_EC_EXPLICIT_CURVE = 0x000, + OPENSSL_EC_NAMED_CURVE = 0x001, }; #ifndef WOLFSSL_EC_TYPE_DEFINED /* guard on redeclaration */ diff --git a/wolfssl/openssl/evp.h b/wolfssl/openssl/evp.h index 871fcf8bc..e333852b6 100644 --- a/wolfssl/openssl/evp.h +++ b/wolfssl/openssl/evp.h @@ -411,6 +411,9 @@ struct WOLFSSL_EVP_PKEY_CTX { int op; /* operation */ int padding; int nbits; +#ifdef HAVE_ECC + int curveNID; +#endif }; struct WOLFSSL_ASN1_PCTX { @@ -624,6 +627,11 @@ WOLFSSL_API const unsigned char* wolfSSL_EVP_PKEY_get0_hmac(const WOLFSSL_EVP_PK WOLFSSL_API int wolfSSL_EVP_PKEY_sign_init(WOLFSSL_EVP_PKEY_CTX *ctx); WOLFSSL_API int wolfSSL_EVP_PKEY_sign(WOLFSSL_EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen, const unsigned char *tbs, size_t tbslen); +WOLFSSL_API int wolfSSL_EVP_PKEY_paramgen_init(WOLFSSL_EVP_PKEY_CTX *ctx); +WOLFSSL_API int wolfSSL_EVP_PKEY_CTX_set_ec_paramgen_curve_nid(WOLFSSL_EVP_PKEY_CTX *ctx, + int nid); +WOLFSSL_API int EVP_PKEY_CTX_set_ec_param_enc(WOLFSSL_EVP_PKEY_CTX *ctx, + int flag); WOLFSSL_API int wolfSSL_EVP_PKEY_keygen_init(WOLFSSL_EVP_PKEY_CTX *ctx); WOLFSSL_API int wolfSSL_EVP_PKEY_keygen(WOLFSSL_EVP_PKEY_CTX *ctx, WOLFSSL_EVP_PKEY **ppkey); @@ -924,6 +932,8 @@ WOLFSSL_API void wolfSSL_EVP_MD_do_all(void (*fn) (const WOLFSSL_EVP_MD *md, #define EVP_MD_CTX_copy_ex wolfSSL_EVP_MD_CTX_copy_ex #define EVP_PKEY_sign_init wolfSSL_EVP_PKEY_sign_init #define EVP_PKEY_sign wolfSSL_EVP_PKEY_sign +#define EVP_PKEY_paramgen_init wolfSSL_EVP_PKEY_paramgen_init +#define EVP_PKEY_CTX_set_ec_paramgen_curve_nid wolfSSL_EVP_PKEY_CTX_set_ec_paramgen_curve_nid #define EVP_PKEY_keygen wolfSSL_EVP_PKEY_keygen #define EVP_PKEY_keygen_init wolfSSL_EVP_PKEY_keygen_init #define EVP_PKEY_bits wolfSSL_EVP_PKEY_bits diff --git a/wolfssl/openssl/ssl.h b/wolfssl/openssl/ssl.h index d5d5de371..edd3d3baa 100644 --- a/wolfssl/openssl/ssl.h +++ b/wolfssl/openssl/ssl.h @@ -298,7 +298,7 @@ typedef STACK_OF(ACCESS_DESCRIPTION) AUTHORITY_INFO_ACCESS; #define SSL_CTX_free wolfSSL_CTX_free #define SSL_free wolfSSL_free #define SSL_shutdown wolfSSL_shutdown -#define SSL_set_timeout wolfSSL_set_timeout +#define SSL_set_timeout wolfSSL_SSL_SESSION_set_timeout #define SSL_CTX_set_quiet_shutdown wolfSSL_CTX_set_quiet_shutdown #define SSL_set_quiet_shutdown wolfSSL_set_quiet_shutdown @@ -1440,8 +1440,9 @@ wolfSSL_X509_STORE_set_verify_cb((WOLFSSL_X509_STORE *)(s), (WOLFSSL_X509_STORE_ #define ERR_LIB_USER 15 #if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) || \ - defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(OPENSSL_ALL) || \ - defined(HAVE_LIGHTY) || defined(HAVE_STUNNEL) + defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(OPENSSL_EXTRA) || \ + defined(HAVE_LIGHTY) || defined(HAVE_STUNNEL) || \ + defined(WOLFSSL_WPAS_SMALL) #include