/* ssl.c * * Copyright (C) 2006-2021 wolfSSL Inc. * * This file is part of wolfSSL. * * wolfSSL is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * wolfSSL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ #ifdef HAVE_CONFIG_H #include #endif #include #if defined(OPENSSL_EXTRA) && !defined(_WIN32) /* turn on GNU extensions for XISASCII */ #undef _GNU_SOURCE #define _GNU_SOURCE #endif #if !defined(WOLFCRYPT_ONLY) || defined(OPENSSL_EXTRA) || \ defined(OPENSSL_EXTRA_X509_SMALL) #include #include #include #include #ifdef NO_INLINE #include #else #define WOLFSSL_MISC_INCLUDED #include #endif #ifdef HAVE_ERRNO_H #include #endif #if !defined(WOLFSSL_ALLOW_NO_SUITES) && !defined(WOLFCRYPT_ONLY) #if defined(NO_DH) && !defined(HAVE_ECC) && !defined(WOLFSSL_STATIC_RSA) \ && !defined(WOLFSSL_STATIC_DH) && !defined(WOLFSSL_STATIC_PSK) \ && !defined(HAVE_CURVE25519) && !defined(HAVE_CURVE448) #error "No cipher suites defined because DH disabled, ECC disabled, and no static suites defined. Please see top of README" #endif #ifdef WOLFSSL_CERT_GEN /* need access to Cert struct for creating certificate */ #include #endif #endif #if !defined(WOLFCRYPT_ONLY) && (defined(OPENSSL_EXTRA) \ || defined(OPENSSL_EXTRA_X509_SMALL) \ || defined(HAVE_WEBSERVER) || defined(WOLFSSL_KEY_GEN)) #include /* openssl headers end, wolfssl internal headers next */ #endif #include #ifndef NO_RSA #include #endif #ifdef OPENSSL_EXTRA /* openssl headers begin */ #include #include #ifndef WOLFCRYPT_ONLY #include #include #endif #include #include #include #include #include #include #include #ifndef WOLFCRYPT_ONLY #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include /* openssl headers end, wolfssl internal headers next */ #include #include #include #include #include #include #include #include #include #include #if defined(HAVE_PQC) #include #endif #if defined(OPENSSL_ALL) || defined(HAVE_STUNNEL) #ifdef HAVE_OCSP #include #endif #include #include #endif /* WITH_STUNNEL */ #if defined(WOLFSSL_SHA512) || defined(WOLFSSL_SHA384) #include #endif #if defined(WOLFCRYPT_HAVE_SRP) && !defined(NO_SHA256) \ && !defined(WC_NO_RNG) #include #endif #if defined(HAVE_FIPS) || defined(HAVE_SELFTEST) #include #endif #if defined(OPENSSL_ALL) && defined(HAVE_PKCS7) #include #endif /* OPENSSL_ALL && HAVE_PKCS7 */ #endif #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) #include int SetIndividualInternal(WOLFSSL_BIGNUM* bn, mp_int* mpi); int SetIndividualExternal(WOLFSSL_BIGNUM** bn, mp_int* mpi); #endif #if defined(WOLFSSL_QT) #include #endif #ifdef NO_ASN #include #endif #endif /* !WOLFCRYPT_ONLY || OPENSSL_EXTRA */ /* * OPENSSL_COMPATIBLE_DEFAULTS: * Enable default behaviour that is compatible with OpenSSL. For example * SSL_CTX by default doesn't verify the loaded certs. Enabling this * should make porting to new projects easier. * WOLFSSL_CHECK_ALERT_ON_ERR: * Check for alerts during the handshake in the event of an error. * NO_SESSION_CACHE_REF: * wolfSSL_get_session on a client will return a reference to the internal * ClientCache by default for backwards compatibility. This define will * make wolfSSL_get_session return a reference to ssl->session. The returned * pointer will be freed with the related WOLFSSL object. */ #define WOLFSSL_EVP_INCLUDED #include "wolfcrypt/src/evp.c" #ifndef WOLFCRYPT_ONLY #define WOLFSSL_PK_INCLUDED #include "src/pk.c" #ifdef OPENSSL_EXTRA /* Global pointer to constant BN on */ static WOLFSSL_BIGNUM* bn_one = NULL; /* WOLFSSL_NO_OPENSSL_RAND_CB: Allows way to reduce code size for * OPENSSL_EXTRA where RAND callbacks are not used */ #ifndef WOLFSSL_NO_OPENSSL_RAND_CB static const WOLFSSL_RAND_METHOD* gRandMethods = NULL; static int gRandMethodsInit = 0; static wolfSSL_Mutex gRandMethodMutex; #endif /* !WOLFSSL_NO_OPENSSL_RAND_CB */ #endif /* OPENSSL_EXTRA */ #if defined(OPENSSL_EXTRA) && defined(HAVE_ECC) const WOLF_EC_NIST_NAME kNistCurves[] = { {XSTR_SIZEOF("P-192"), "P-192", NID_X9_62_prime192v1}, {XSTR_SIZEOF("P-256"), "P-256", NID_X9_62_prime256v1}, {XSTR_SIZEOF("P-112"), "P-112", NID_secp112r1}, {XSTR_SIZEOF("P-112-2"), "P-112-2", NID_secp112r2}, {XSTR_SIZEOF("P-128"), "P-128", NID_secp128r1}, {XSTR_SIZEOF("P-128-2"), "P-128-2", NID_secp128r2}, {XSTR_SIZEOF("P-160"), "P-160", NID_secp160r1}, {XSTR_SIZEOF("P-160-2"), "P-160-2", NID_secp160r2}, {XSTR_SIZEOF("P-224"), "P-224", NID_secp224r1}, {XSTR_SIZEOF("P-384"), "P-384", NID_secp384r1}, {XSTR_SIZEOF("P-521"), "P-521", NID_secp521r1}, {XSTR_SIZEOF("K-160"), "K-160", NID_secp160k1}, {XSTR_SIZEOF("K-192"), "K-192", NID_secp192k1}, {XSTR_SIZEOF("K-224"), "K-224", NID_secp224k1}, {XSTR_SIZEOF("K-256"), "K-256", NID_secp256k1}, {XSTR_SIZEOF("B-160"), "B-160", NID_brainpoolP160r1}, {XSTR_SIZEOF("B-192"), "B-192", NID_brainpoolP192r1}, {XSTR_SIZEOF("B-224"), "B-224", NID_brainpoolP224r1}, {XSTR_SIZEOF("B-256"), "B-256", NID_brainpoolP256r1}, {XSTR_SIZEOF("B-320"), "B-320", NID_brainpoolP320r1}, {XSTR_SIZEOF("B-384"), "B-384", NID_brainpoolP384r1}, {XSTR_SIZEOF("B-512"), "B-512", NID_brainpoolP512r1}, #ifdef HAVE_PQC {XSTR_SIZEOF("KYBER_LEVEL1"), "KYBER_LEVEL1", WOLFSSL_KYBER_LEVEL1}, {XSTR_SIZEOF("KYBER_LEVEL3"), "KYBER_LEVEL3", WOLFSSL_KYBER_LEVEL3}, {XSTR_SIZEOF("KYBER_LEVEL5"), "KYBER_LEVEL5", WOLFSSL_KYBER_LEVEL5}, {XSTR_SIZEOF("NTRU_HPS_LEVEL1"), "NTRU_HPS_LEVEL1", WOLFSSL_NTRU_HPS_LEVEL1}, {XSTR_SIZEOF("NTRU_HPS_LEVEL3"), "NTRU_HPS_LEVEL3", WOLFSSL_NTRU_HPS_LEVEL3}, {XSTR_SIZEOF("NTRU_HPS_LEVEL5"), "NTRU_HPS_LEVEL5", WOLFSSL_NTRU_HPS_LEVEL5}, {XSTR_SIZEOF("NTRU_HRSS_LEVEL3"), "NTRU_HRSS_LEVEL3", WOLFSSL_NTRU_HRSS_LEVEL3}, {XSTR_SIZEOF("SABER_LEVEL1"), "SABER_LEVEL1", WOLFSSL_SABER_LEVEL1}, {XSTR_SIZEOF("SABER_LEVEL3"), "SABER_LEVEL3", WOLFSSL_SABER_LEVEL3}, {XSTR_SIZEOF("SABER_LEVEL5"), "SABER_LEVEL5", WOLFSSL_SABER_LEVEL5}, {XSTR_SIZEOF("KYBER_90S_LEVEL1"), "KYBER_90S_LEVEL1", WOLFSSL_KYBER_90S_LEVEL1}, {XSTR_SIZEOF("KYBER_90S_LEVEL3"), "KYBER_90S_LEVEL3", WOLFSSL_KYBER_90S_LEVEL3}, {XSTR_SIZEOF("KYBER_90S_LEVEL5"), "KYBER_90S_LEVEL5", WOLFSSL_KYBER_90S_LEVEL5}, {XSTR_SIZEOF("P256_NTRU_HPS_LEVEL1"), "P256_NTRU_HPS_LEVEL1", WOLFSSL_P256_NTRU_HPS_LEVEL1}, {XSTR_SIZEOF("P384_NTRU_HPS_LEVEL3"), "P384_NTRU_HPS_LEVEL3", WOLFSSL_P384_NTRU_HPS_LEVEL3}, {XSTR_SIZEOF("P521_NTRU_HPS_LEVEL5"), "P521_NTRU_HPS_LEVEL5", WOLFSSL_P521_NTRU_HPS_LEVEL5}, {XSTR_SIZEOF("P384_NTRU_HRSS_LEVEL3"), "P384_NTRU_HRSS_LEVEL3", WOLFSSL_P384_NTRU_HRSS_LEVEL3}, {XSTR_SIZEOF("P256_SABER_LEVEL1"), "P256_SABER_LEVEL1", WOLFSSL_P256_SABER_LEVEL1}, {XSTR_SIZEOF("P384_SABER_LEVEL3"), "P384_SABER_LEVEL3", WOLFSSL_P384_SABER_LEVEL3}, {XSTR_SIZEOF("P521_SABER_LEVEL5"), "P521_SABER_LEVEL5", WOLFSSL_P521_SABER_LEVEL5}, {XSTR_SIZEOF("P256_KYBER_LEVEL1"), "P256_KYBER_LEVEL1", WOLFSSL_P256_KYBER_LEVEL1}, {XSTR_SIZEOF("P384_KYBER_LEVEL3"), "P384_KYBER_LEVEL3", WOLFSSL_P384_KYBER_LEVEL3}, {XSTR_SIZEOF("P521_KYBER_LEVEL5"), "P521_KYBER_LEVEL5", WOLFSSL_P521_KYBER_LEVEL5}, {XSTR_SIZEOF("P256_KYBER_90S_LEVEL1"), "P256_KYBER_90S_LEVEL1", WOLFSSL_P256_KYBER_90S_LEVEL1}, {XSTR_SIZEOF("P384_KYBER_90S_LEVEL3"), "P384_KYBER_90S_LEVEL3", WOLFSSL_P384_KYBER_90S_LEVEL3}, {XSTR_SIZEOF("P521_KYBER_90S_LEVEL5"), "P521_KYBER_90S_LEVEL5", WOLFSSL_P521_KYBER_90S_LEVEL5}, #endif {0, NULL, 0}, }; #endif #if defined(WOLFSSL_RENESAS_TSIP_TLS) || defined(WOLFSSL_RENESAS_SCEPROTECT) #include #endif #ifdef WOLFSSL_SESSION_EXPORT /* Used to import a serialized TLS session. * WARNING: buf contains sensitive information about the state and is best to be * encrypted before storing if stored. * * @param ssl WOLFSSL structure to import the session into * @param buf serialized session * @param sz size of buffer 'buf' * @return the number of bytes read from buffer 'buf' */ int wolfSSL_tls_import(WOLFSSL* ssl, const unsigned char* buf, unsigned int sz) { if (ssl == NULL || buf == NULL) { return BAD_FUNC_ARG; } return wolfSSL_session_import_internal(ssl, buf, sz, WOLFSSL_EXPORT_TLS); } /* Used to export a serialized TLS session. * WARNING: buf contains sensitive information about the state and is best to be * encrypted before storing if stored. * * @param ssl WOLFSSL structure to export the session from * @param buf output of serialized session * @param sz size in bytes set in 'buf' * @return the number of bytes written into buffer 'buf' */ int wolfSSL_tls_export(WOLFSSL* ssl, unsigned char* buf, unsigned int* sz) { if (ssl == NULL || sz == NULL) { return BAD_FUNC_ARG; } return wolfSSL_session_export_internal(ssl, buf, sz, WOLFSSL_EXPORT_TLS); } #ifdef WOLFSSL_DTLS int wolfSSL_dtls_import(WOLFSSL* ssl, const unsigned char* buf, unsigned int sz) { WOLFSSL_ENTER("wolfSSL_session_import"); if (ssl == NULL || buf == NULL) { return BAD_FUNC_ARG; } /* sanity checks on buffer and protocol are done in internal function */ return wolfSSL_session_import_internal(ssl, buf, sz, WOLFSSL_EXPORT_DTLS); } /* Sets the function to call for serializing the session. This function is * called right after the handshake is completed. */ int wolfSSL_CTX_dtls_set_export(WOLFSSL_CTX* ctx, wc_dtls_export func) { WOLFSSL_ENTER("wolfSSL_CTX_dtls_set_export"); /* purposefully allow func to be NULL */ if (ctx == NULL) { return BAD_FUNC_ARG; } ctx->dtls_export = func; return WOLFSSL_SUCCESS; } /* Sets the function in WOLFSSL struct to call for serializing the session. This * function is called right after the handshake is completed. */ int wolfSSL_dtls_set_export(WOLFSSL* ssl, wc_dtls_export func) { WOLFSSL_ENTER("wolfSSL_dtls_set_export"); /* purposefully allow func to be NULL */ if (ssl == NULL) { return BAD_FUNC_ARG; } ssl->dtls_export = func; return WOLFSSL_SUCCESS; } /* This function allows for directly serializing a session rather than using * callbacks. It has less overhead by removing a temporary buffer and gives * control over when the session gets serialized. When using callbacks the * session is always serialized immediately after the handshake is finished. * * buf is the argument to contain the serialized session * sz is the size of the buffer passed in * ssl is the WOLFSSL struct to serialize * returns the size of serialized session on success, 0 on no action, and * negative value on error */ int wolfSSL_dtls_export(WOLFSSL* ssl, unsigned char* buf, unsigned int* sz) { WOLFSSL_ENTER("wolfSSL_dtls_export"); if (ssl == NULL || sz == NULL) { return BAD_FUNC_ARG; } if (buf == NULL) { *sz = MAX_EXPORT_BUFFER; return 0; } /* if not DTLS do nothing */ if (!ssl->options.dtls) { WOLFSSL_MSG("Currently only DTLS export is supported"); return 0; } /* copy over keys, options, and dtls state struct */ return wolfSSL_session_export_internal(ssl, buf, sz, WOLFSSL_EXPORT_DTLS); } /* This function is similar to wolfSSL_dtls_export but only exports the portion * of the WOLFSSL structure related to the state of the connection, i.e. peer * sequence number, epoch, AEAD state etc. * * buf is the argument to contain the serialized state, if null then set "sz" to * buffer size required * sz is the size of the buffer passed in * ssl is the WOLFSSL struct to serialize * returns the size of serialized session on success, 0 on no action, and * negative value on error */ int wolfSSL_dtls_export_state_only(WOLFSSL* ssl, unsigned char* buf, unsigned int* sz) { WOLFSSL_ENTER("wolfSSL_dtls_export_state_only"); if (ssl == NULL || sz == NULL) { return BAD_FUNC_ARG; } if (buf == NULL) { *sz = MAX_EXPORT_STATE_BUFFER; return 0; } /* if not DTLS do nothing */ if (!ssl->options.dtls) { WOLFSSL_MSG("Currently only DTLS export state is supported"); return 0; } /* copy over keys, options, and dtls state struct */ return wolfSSL_dtls_export_state_internal(ssl, buf, *sz); } /* returns 0 on success */ int wolfSSL_send_session(WOLFSSL* ssl) { int ret; byte* buf; word32 bufSz = MAX_EXPORT_BUFFER; WOLFSSL_ENTER("wolfSSL_send_session"); if (ssl == NULL) { return BAD_FUNC_ARG; } buf = (byte*)XMALLOC(bufSz, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); if (buf == NULL) { return MEMORY_E; } /* if not DTLS do nothing */ if (!ssl->options.dtls) { XFREE(buf, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); WOLFSSL_MSG("Currently only DTLS export is supported"); return 0; } /* copy over keys, options, and dtls state struct */ ret = wolfSSL_session_export_internal(ssl, buf, &bufSz, WOLFSSL_EXPORT_DTLS); if (ret < 0) { XFREE(buf, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); return ret; } /* if no error ret has size of buffer */ ret = ssl->dtls_export(ssl, buf, ret, NULL); if (ret != WOLFSSL_SUCCESS) { XFREE(buf, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); return ret; } XFREE(buf, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); return 0; } #endif /* WOLFSSL_DTLS */ #endif /* WOLFSSL_SESSION_EXPORT */ /* prevent multiple mutex initializations */ static volatile WOLFSSL_GLOBAL int initRefCount = 0; static WOLFSSL_GLOBAL wolfSSL_Mutex count_mutex; /* init ref count mutex */ static WOLFSSL_GLOBAL int count_mutex_valid = 0; /* Create a new WOLFSSL_CTX struct and return the pointer to created struct. WOLFSSL_METHOD pointer passed in is given to ctx to manage. This function frees the passed in WOLFSSL_METHOD struct on failure and on success is freed when ctx is freed. */ WOLFSSL_CTX* wolfSSL_CTX_new_ex(WOLFSSL_METHOD* method, void* heap) { WOLFSSL_CTX* ctx = NULL; WOLFSSL_ENTER("wolfSSL_CTX_new_ex"); if (initRefCount == 0) { /* user no longer forced to call Init themselves */ int ret = wolfSSL_Init(); if (ret != WOLFSSL_SUCCESS) { WOLFSSL_MSG("wolfSSL_Init failed"); WOLFSSL_LEAVE("WOLFSSL_CTX_new", 0); if (method != NULL) { XFREE(method, heap, DYNAMIC_TYPE_METHOD); } return NULL; } } if (method == NULL) return ctx; ctx = (WOLFSSL_CTX*)XMALLOC(sizeof(WOLFSSL_CTX), heap, DYNAMIC_TYPE_CTX); if (ctx) { int ret; ret = InitSSL_Ctx(ctx, method, heap); #ifdef WOLFSSL_STATIC_MEMORY if (heap != NULL) { ctx->onHeapHint = 1; /* free the memory back to heap when done */ } #endif if (ret < 0) { WOLFSSL_MSG("Init CTX failed"); wolfSSL_CTX_free(ctx); ctx = NULL; } #if defined(OPENSSL_EXTRA) && defined(WOLFCRYPT_HAVE_SRP) \ && !defined(NO_SHA256) && !defined(WC_NO_RNG) else { ctx->srp = (Srp*)XMALLOC(sizeof(Srp), heap, DYNAMIC_TYPE_SRP); if (ctx->srp == NULL){ WOLFSSL_MSG("Init CTX failed"); wolfSSL_CTX_free(ctx); return NULL; } XMEMSET(ctx->srp, 0, sizeof(Srp)); } #endif } else { WOLFSSL_MSG("Alloc CTX failed, method freed"); XFREE(method, heap, DYNAMIC_TYPE_METHOD); } #ifdef OPENSSL_COMPATIBLE_DEFAULTS if (ctx) { wolfSSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); wolfSSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); if (wolfSSL_CTX_set_min_proto_version(ctx, SSL3_VERSION) != WOLFSSL_SUCCESS || #ifdef HAVE_ANON wolfSSL_CTX_allow_anon_cipher(ctx) != WOLFSSL_SUCCESS || #endif wolfSSL_CTX_set_group_messages(ctx) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("Setting OpenSSL CTX defaults failed"); wolfSSL_CTX_free(ctx); ctx = NULL; } } #endif WOLFSSL_LEAVE("WOLFSSL_CTX_new", 0); return ctx; } WOLFSSL_ABI WOLFSSL_CTX* wolfSSL_CTX_new(WOLFSSL_METHOD* method) { #ifdef WOLFSSL_HEAP_TEST /* if testing the heap hint then set top level CTX to have test value */ return wolfSSL_CTX_new_ex(method, (void*)WOLFSSL_HEAP_TEST); #else return wolfSSL_CTX_new_ex(method, NULL); #endif } /* increases CTX reference count to track proper time to "free" */ int wolfSSL_CTX_up_ref(WOLFSSL_CTX* ctx) { int refCount = SSL_CTX_RefCount(ctx, 1); return ((refCount > 1) ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE); } WOLFSSL_ABI void wolfSSL_CTX_free(WOLFSSL_CTX* ctx) { WOLFSSL_ENTER("SSL_CTX_free"); if (ctx) { #if defined(OPENSSL_EXTRA) && defined(WOLFCRYPT_HAVE_SRP) \ && !defined(NO_SHA256) && !defined(WC_NO_RNG) if (ctx->srp != NULL) { if (ctx->srp_password != NULL){ XFREE(ctx->srp_password, ctx->heap, DYNAMIC_TYPE_SRP); ctx->srp_password = NULL; } wc_SrpTerm(ctx->srp); XFREE(ctx->srp, ctx->heap, DYNAMIC_TYPE_SRP); ctx->srp = NULL; } #endif FreeSSL_Ctx(ctx); } WOLFSSL_LEAVE("SSL_CTX_free", 0); } #ifdef HAVE_ENCRYPT_THEN_MAC /** * Sets whether Encrypt-Then-MAC extension can be negotiated against context. * The default value: enabled. * * ctx SSL/TLS context. * set Whether to allow or not: 1 is allow and 0 is disallow. * returns WOLFSSL_SUCCESS */ int wolfSSL_CTX_AllowEncryptThenMac(WOLFSSL_CTX *ctx, int set) { ctx->disallowEncThenMac = !set; return WOLFSSL_SUCCESS; } /** * Sets whether Encrypt-Then-MAC extension can be negotiated against context. * The default value comes from context. * * ctx SSL/TLS context. * set Whether to allow or not: 1 is allow and 0 is disallow. * returns WOLFSSL_SUCCESS */ int wolfSSL_AllowEncryptThenMac(WOLFSSL *ssl, int set) { ssl->options.disallowEncThenMac = !set; return WOLFSSL_SUCCESS; } #endif #ifdef SINGLE_THREADED /* no locking in single threaded mode, allow a CTX level rng to be shared with * WOLFSSL objects, WOLFSSL_SUCCESS on ok */ int wolfSSL_CTX_new_rng(WOLFSSL_CTX* ctx) { WC_RNG* rng; int ret; if (ctx == NULL) { return BAD_FUNC_ARG; } rng = (WC_RNG*)XMALLOC(sizeof(WC_RNG), ctx->heap, DYNAMIC_TYPE_RNG); if (rng == NULL) { return MEMORY_E; } #ifndef HAVE_FIPS ret = wc_InitRng_ex(rng, ctx->heap, ctx->devId); #else ret = wc_InitRng(rng); #endif if (ret != 0) { XFREE(rng, ctx->heap, DYNAMIC_TYPE_RNG); return ret; } ctx->rng = rng; return WOLFSSL_SUCCESS; } #endif WOLFSSL_ABI WOLFSSL* wolfSSL_new(WOLFSSL_CTX* ctx) { WOLFSSL* ssl = NULL; int ret = 0; WOLFSSL_ENTER("SSL_new"); if (ctx == NULL) return ssl; ssl = (WOLFSSL*) XMALLOC(sizeof(WOLFSSL), ctx->heap, DYNAMIC_TYPE_SSL); if (ssl) if ( (ret = InitSSL(ssl, ctx, 0)) < 0) { FreeSSL(ssl, ctx->heap); ssl = 0; } WOLFSSL_LEAVE("SSL_new", ret); (void)ret; return ssl; } WOLFSSL_ABI void wolfSSL_free(WOLFSSL* ssl) { WOLFSSL_ENTER("SSL_free"); if (ssl) FreeSSL(ssl, ssl->ctx->heap); WOLFSSL_LEAVE("SSL_free", 0); } int wolfSSL_is_server(WOLFSSL* ssl) { if (ssl == NULL) return BAD_FUNC_ARG; return ssl->options.side == WOLFSSL_SERVER_END; } #ifdef HAVE_WRITE_DUP /* * Release resources around WriteDup object * * ssl WOLFSSL object * * no return, destruction so make best attempt */ void FreeWriteDup(WOLFSSL* ssl) { int doFree = 0; WOLFSSL_ENTER("FreeWriteDup"); if (ssl->dupWrite) { if (wc_LockMutex(&ssl->dupWrite->dupMutex) == 0) { ssl->dupWrite->dupCount--; if (ssl->dupWrite->dupCount == 0) { doFree = 1; } else { WOLFSSL_MSG("WriteDup count not zero, no full free"); } wc_UnLockMutex(&ssl->dupWrite->dupMutex); } } if (doFree) { WOLFSSL_MSG("Doing WriteDup full free, count to zero"); wc_FreeMutex(&ssl->dupWrite->dupMutex); XFREE(ssl->dupWrite, ssl->heap, DYNAMIC_TYPE_WRITEDUP); } } /* * duplicate existing ssl members into dup needed for writing * * dup write only WOLFSSL * ssl existing WOLFSSL * * 0 on success */ static int DupSSL(WOLFSSL* dup, WOLFSSL* ssl) { /* shared dupWrite setup */ ssl->dupWrite = (WriteDup*)XMALLOC(sizeof(WriteDup), ssl->heap, DYNAMIC_TYPE_WRITEDUP); if (ssl->dupWrite == NULL) { return MEMORY_E; } XMEMSET(ssl->dupWrite, 0, sizeof(WriteDup)); if (wc_InitMutex(&ssl->dupWrite->dupMutex) != 0) { XFREE(ssl->dupWrite, ssl->heap, DYNAMIC_TYPE_WRITEDUP); ssl->dupWrite = NULL; return BAD_MUTEX_E; } ssl->dupWrite->dupCount = 2; /* both sides have a count to start */ dup->dupWrite = ssl->dupWrite; /* each side uses */ /* copy write parts over to dup writer */ XMEMCPY(&dup->specs, &ssl->specs, sizeof(CipherSpecs)); XMEMCPY(&dup->options, &ssl->options, sizeof(Options)); XMEMCPY(&dup->keys, &ssl->keys, sizeof(Keys)); XMEMCPY(&dup->encrypt, &ssl->encrypt, sizeof(Ciphers)); /* dup side now owns encrypt/write ciphers */ XMEMSET(&ssl->encrypt, 0, sizeof(Ciphers)); dup->IOCB_WriteCtx = ssl->IOCB_WriteCtx; dup->CBIOSend = ssl->CBIOSend; #ifdef OPENSSL_EXTRA dup->cbioFlag = ssl->cbioFlag; #endif dup->wfd = ssl->wfd; dup->wflags = ssl->wflags; #ifndef WOLFSSL_AEAD_ONLY dup->hmac = ssl->hmac; #endif #ifdef HAVE_TRUNCATED_HMAC dup->truncated_hmac = ssl->truncated_hmac; #endif /* unique side dup setup */ dup->dupSide = WRITE_DUP_SIDE; ssl->dupSide = READ_DUP_SIDE; return 0; } /* * duplicate a WOLFSSL object post handshake for writing only * turn existing object into read only. Allows concurrent access from two * different threads. * * ssl existing WOLFSSL object * * return dup'd WOLFSSL object on success */ WOLFSSL* wolfSSL_write_dup(WOLFSSL* ssl) { WOLFSSL* dup = NULL; int ret = 0; (void)ret; WOLFSSL_ENTER("wolfSSL_write_dup"); if (ssl == NULL) { return ssl; } if (ssl->options.handShakeDone == 0) { WOLFSSL_MSG("wolfSSL_write_dup called before handshake complete"); return NULL; } if (ssl->dupWrite) { WOLFSSL_MSG("wolfSSL_write_dup already called once"); return NULL; } dup = (WOLFSSL*) XMALLOC(sizeof(WOLFSSL), ssl->ctx->heap, DYNAMIC_TYPE_SSL); if (dup) { if ( (ret = InitSSL(dup, ssl->ctx, 1)) < 0) { FreeSSL(dup, ssl->ctx->heap); dup = NULL; } else if ( (ret = DupSSL(dup, ssl)) < 0) { FreeSSL(dup, ssl->ctx->heap); dup = NULL; } } WOLFSSL_LEAVE("wolfSSL_write_dup", ret); return dup; } /* * Notify write dup side of fatal error or close notify * * ssl WOLFSSL object * err Notify err * * 0 on success */ int NotifyWriteSide(WOLFSSL* ssl, int err) { int ret; WOLFSSL_ENTER("NotifyWriteSide"); ret = wc_LockMutex(&ssl->dupWrite->dupMutex); if (ret == 0) { ssl->dupWrite->dupErr = err; ret = wc_UnLockMutex(&ssl->dupWrite->dupMutex); } return ret; } #endif /* HAVE_WRITE_DUP */ #ifdef HAVE_POLY1305 /* set if to use old poly 1 for yes 0 to use new poly */ int wolfSSL_use_old_poly(WOLFSSL* ssl, int value) { (void)ssl; (void)value; #ifndef WOLFSSL_NO_TLS12 WOLFSSL_ENTER("SSL_use_old_poly"); WOLFSSL_MSG("Warning SSL connection auto detects old/new and this function" "is depreciated"); ssl->options.oldPoly = (word16)value; WOLFSSL_LEAVE("SSL_use_old_poly", 0); #endif return 0; } #endif WOLFSSL_ABI int wolfSSL_set_fd(WOLFSSL* ssl, int fd) { int ret; WOLFSSL_ENTER("SSL_set_fd"); if (ssl == NULL) { return BAD_FUNC_ARG; } ret = wolfSSL_set_read_fd(ssl, fd); if (ret == WOLFSSL_SUCCESS) { ret = wolfSSL_set_write_fd(ssl, fd); } return ret; } #ifdef WOLFSSL_DTLS int wolfSSL_set_dtls_fd_connected(WOLFSSL* ssl, int fd) { int ret; WOLFSSL_ENTER("SSL_set_dtls_fd_connected"); if (ssl == NULL) { return BAD_FUNC_ARG; } ret = wolfSSL_set_fd(ssl, fd); if (ret == WOLFSSL_SUCCESS) ssl->buffers.dtlsCtx.connected = 1; return ret; } #endif int wolfSSL_set_read_fd(WOLFSSL* ssl, int fd) { WOLFSSL_ENTER("SSL_set_read_fd"); if (ssl == NULL) { return BAD_FUNC_ARG; } ssl->rfd = fd; /* not used directly to allow IO callbacks */ ssl->IOCB_ReadCtx = &ssl->rfd; #ifdef WOLFSSL_DTLS ssl->buffers.dtlsCtx.connected = 0; if (ssl->options.dtls) { ssl->IOCB_ReadCtx = &ssl->buffers.dtlsCtx; ssl->buffers.dtlsCtx.rfd = fd; } #endif WOLFSSL_LEAVE("SSL_set_read_fd", WOLFSSL_SUCCESS); return WOLFSSL_SUCCESS; } int wolfSSL_set_write_fd(WOLFSSL* ssl, int fd) { WOLFSSL_ENTER("SSL_set_write_fd"); if (ssl == NULL) { return BAD_FUNC_ARG; } ssl->wfd = fd; /* not used directly to allow IO callbacks */ ssl->IOCB_WriteCtx = &ssl->wfd; #ifdef WOLFSSL_DTLS ssl->buffers.dtlsCtx.connected = 0; if (ssl->options.dtls) { ssl->IOCB_WriteCtx = &ssl->buffers.dtlsCtx; ssl->buffers.dtlsCtx.wfd = fd; } #endif WOLFSSL_LEAVE("SSL_set_write_fd", WOLFSSL_SUCCESS); return WOLFSSL_SUCCESS; } /** * Get the name of cipher at priority level passed in. */ char* wolfSSL_get_cipher_list(int priority) { const CipherSuiteInfo* ciphers = GetCipherNames(); if (priority >= GetCipherNamesSize() || priority < 0) { return 0; } return (char*)ciphers[priority].name; } /** * Get the name of cipher at priority level passed in. */ char* wolfSSL_get_cipher_list_ex(WOLFSSL* ssl, int priority) { if (ssl == NULL) { return NULL; } else { const char* cipher; if ((cipher = wolfSSL_get_cipher_name_internal(ssl)) != NULL) { if (priority == 0) { return (char*)cipher; } else { return NULL; } } else { return wolfSSL_get_cipher_list(priority); } } } int wolfSSL_get_ciphers(char* buf, int len) { const CipherSuiteInfo* ciphers = GetCipherNames(); int ciphersSz = GetCipherNamesSize(); int i; int cipherNameSz; if (buf == NULL || len <= 0) return BAD_FUNC_ARG; /* Add each member to the buffer delimited by a : */ for (i = 0; i < ciphersSz; i++) { cipherNameSz = (int)XSTRLEN(ciphers[i].name); if (cipherNameSz + 1 < len) { XSTRNCPY(buf, ciphers[i].name, len); buf += cipherNameSz; if (i < ciphersSz - 1) *buf++ = ':'; *buf = 0; len -= cipherNameSz + 1; } else return BUFFER_E; } return WOLFSSL_SUCCESS; } #ifndef NO_ERROR_STRINGS /* places a list of all supported cipher suites in TLS_* format into "buf" * return WOLFSSL_SUCCESS on success */ int wolfSSL_get_ciphers_iana(char* buf, int len) { const CipherSuiteInfo* ciphers = GetCipherNames(); int ciphersSz = GetCipherNamesSize(); int i; int cipherNameSz; if (buf == NULL || len <= 0) return BAD_FUNC_ARG; /* Add each member to the buffer delimited by a : */ for (i = 0; i < ciphersSz; i++) { #ifndef NO_CIPHER_SUITE_ALIASES if (ciphers[i].flags & WOLFSSL_CIPHER_SUITE_FLAG_NAMEALIAS) continue; #endif cipherNameSz = (int)XSTRLEN(ciphers[i].name_iana); if (cipherNameSz + 1 < len) { XSTRNCPY(buf, ciphers[i].name_iana, len); buf += cipherNameSz; if (i < ciphersSz - 1) *buf++ = ':'; *buf = 0; len -= cipherNameSz + 1; } else return BUFFER_E; } return WOLFSSL_SUCCESS; } #endif /* NO_ERROR_STRINGS */ const char* wolfSSL_get_shared_ciphers(WOLFSSL* ssl, char* buf, int len) { const char* cipher; if (ssl == NULL) return NULL; cipher = wolfSSL_get_cipher_name_iana(ssl); len = min(len, (int)(XSTRLEN(cipher) + 1)); XMEMCPY(buf, cipher, len); return buf; } int wolfSSL_get_fd(const WOLFSSL* ssl) { int fd = -1; WOLFSSL_ENTER("SSL_get_fd"); if (ssl) { fd = ssl->rfd; } WOLFSSL_LEAVE("SSL_get_fd", fd); return fd; } int wolfSSL_dtls(WOLFSSL* ssl) { int dtlsOpt = 0; if (ssl) dtlsOpt = ssl->options.dtls; return dtlsOpt; } #if !defined(NO_CERTS) /* Set whether mutual authentication is required for connections. * Server side only. * * ctx The SSL/TLS CTX object. * req 1 to indicate required and 0 when not. * returns BAD_FUNC_ARG when ctx is NULL, SIDE_ERROR when not a server and * 0 on success. */ int wolfSSL_CTX_mutual_auth(WOLFSSL_CTX* ctx, int req) { if (ctx == NULL) return BAD_FUNC_ARG; if (ctx->method->side == WOLFSSL_CLIENT_END) return SIDE_ERROR; ctx->mutualAuth = (byte)req; return 0; } /* Set whether mutual authentication is required for the connection. * Server side only. * * ssl The SSL/TLS object. * req 1 to indicate required and 0 when not. * returns BAD_FUNC_ARG when ssl is NULL, or not using TLS v1.3, * SIDE_ERROR when not a client and 0 on success. */ int wolfSSL_mutual_auth(WOLFSSL* ssl, int req) { if (ssl == NULL) return BAD_FUNC_ARG; if (ssl->options.side == WOLFSSL_SERVER_END) return SIDE_ERROR; ssl->options.mutualAuth = (word16)req; return 0; } #endif /* NO_CERTS */ #ifdef WOLFSSL_WOLFSENTRY_HOOKS int wolfSSL_CTX_set_AcceptFilter( WOLFSSL_CTX *ctx, NetworkFilterCallback_t AcceptFilter, void *AcceptFilter_arg) { if (ctx == NULL) return BAD_FUNC_ARG; ctx->AcceptFilter = AcceptFilter; ctx->AcceptFilter_arg = AcceptFilter_arg; return 0; } int wolfSSL_set_AcceptFilter( WOLFSSL *ssl, NetworkFilterCallback_t AcceptFilter, void *AcceptFilter_arg) { if (ssl == NULL) return BAD_FUNC_ARG; ssl->AcceptFilter = AcceptFilter; ssl->AcceptFilter_arg = AcceptFilter_arg; return 0; } int wolfSSL_CTX_set_ConnectFilter( WOLFSSL_CTX *ctx, NetworkFilterCallback_t ConnectFilter, void *ConnectFilter_arg) { if (ctx == NULL) return BAD_FUNC_ARG; ctx->ConnectFilter = ConnectFilter; ctx->ConnectFilter_arg = ConnectFilter_arg; return 0; } int wolfSSL_set_ConnectFilter( WOLFSSL *ssl, NetworkFilterCallback_t ConnectFilter, void *ConnectFilter_arg) { if (ssl == NULL) return BAD_FUNC_ARG; ssl->ConnectFilter = ConnectFilter; ssl->ConnectFilter_arg = ConnectFilter_arg; return 0; } #endif /* WOLFSSL_WOLFSENTRY_HOOKS */ #ifndef WOLFSSL_LEANPSK int wolfSSL_dtls_set_peer(WOLFSSL* ssl, void* peer, unsigned int peerSz) { #ifdef WOLFSSL_DTLS void* sa; if (ssl == NULL) return WOLFSSL_FAILURE; if (peer == NULL || peerSz == 0) { if (ssl->buffers.dtlsCtx.peer.sa != NULL) XFREE(ssl->buffers.dtlsCtx.peer.sa,ssl->heap,DYNAMIC_TYPE_SOCKADDR); ssl->buffers.dtlsCtx.peer.sa = NULL; ssl->buffers.dtlsCtx.peer.sz = 0; ssl->buffers.dtlsCtx.peer.bufSz = 0; ssl->buffers.dtlsCtx.userSet = 0; return WOLFSSL_SUCCESS; } sa = (void*)XMALLOC(peerSz, ssl->heap, DYNAMIC_TYPE_SOCKADDR); if (sa != NULL) { if (ssl->buffers.dtlsCtx.peer.sa != NULL) { XFREE(ssl->buffers.dtlsCtx.peer.sa,ssl->heap,DYNAMIC_TYPE_SOCKADDR); ssl->buffers.dtlsCtx.peer.sa = NULL; } XMEMCPY(sa, peer, peerSz); ssl->buffers.dtlsCtx.peer.sa = sa; ssl->buffers.dtlsCtx.peer.sz = peerSz; ssl->buffers.dtlsCtx.peer.bufSz = peerSz; ssl->buffers.dtlsCtx.userSet = 1; return WOLFSSL_SUCCESS; } return WOLFSSL_FAILURE; #else (void)ssl; (void)peer; (void)peerSz; return WOLFSSL_NOT_IMPLEMENTED; #endif } int wolfSSL_dtls_get_peer(WOLFSSL* ssl, void* peer, unsigned int* peerSz) { #ifdef WOLFSSL_DTLS if (ssl == NULL) { return WOLFSSL_FAILURE; } if (peer != NULL && peerSz != NULL && *peerSz >= ssl->buffers.dtlsCtx.peer.sz && ssl->buffers.dtlsCtx.peer.sa != NULL) { *peerSz = ssl->buffers.dtlsCtx.peer.sz; XMEMCPY(peer, ssl->buffers.dtlsCtx.peer.sa, *peerSz); return WOLFSSL_SUCCESS; } return WOLFSSL_FAILURE; #else (void)ssl; (void)peer; (void)peerSz; return WOLFSSL_NOT_IMPLEMENTED; #endif } #if defined(WOLFSSL_SCTP) && defined(WOLFSSL_DTLS) int wolfSSL_CTX_dtls_set_sctp(WOLFSSL_CTX* ctx) { WOLFSSL_ENTER("wolfSSL_CTX_dtls_set_sctp()"); if (ctx == NULL) return BAD_FUNC_ARG; ctx->dtlsSctp = 1; return WOLFSSL_SUCCESS; } int wolfSSL_dtls_set_sctp(WOLFSSL* ssl) { WOLFSSL_ENTER("wolfSSL_dtls_set_sctp()"); if (ssl == NULL) return BAD_FUNC_ARG; ssl->options.dtlsSctp = 1; return WOLFSSL_SUCCESS; } #endif /* WOLFSSL_DTLS && WOLFSSL_SCTP */ #if (defined(WOLFSSL_SCTP) || defined(WOLFSSL_DTLS_MTU)) && \ defined(WOLFSSL_DTLS) int wolfSSL_CTX_dtls_set_mtu(WOLFSSL_CTX* ctx, word16 newMtu) { if (ctx == NULL || newMtu > MAX_RECORD_SIZE) return BAD_FUNC_ARG; ctx->dtlsMtuSz = newMtu; return WOLFSSL_SUCCESS; } int wolfSSL_dtls_set_mtu(WOLFSSL* ssl, word16 newMtu) { if (ssl == NULL) return BAD_FUNC_ARG; if (newMtu > MAX_RECORD_SIZE) { ssl->error = BAD_FUNC_ARG; return WOLFSSL_FAILURE; } ssl->dtlsMtuSz = newMtu; return WOLFSSL_SUCCESS; } #endif /* WOLFSSL_DTLS && (WOLFSSL_SCTP || WOLFSSL_DTLS_MTU) */ #ifdef WOLFSSL_SRTP static const WOLFSSL_SRTP_PROTECTION_PROFILE gSrtpProfiles[] = { /* AES CCM 128, Salt:112-bits, Auth HMAC-SHA1 Tag: 80-bits * (master_key:128bits + master_salt:112bits) * 2 = 480 bits (60) */ {"SRTP_AES128_CM_SHA1_80", SRTP_AES128_CM_SHA1_80, (((128 + 112) * 2) / 8) }, /* AES CCM 128, Salt:112-bits, Auth HMAC-SHA1 Tag: 32-bits * (master_key:128bits + master_salt:112bits) * 2 = 480 bits (60) */ {"SRTP_AES128_CM_SHA1_32", SRTP_AES128_CM_SHA1_32, (((128 + 112) * 2) / 8) }, /* NULL Cipher, Salt:112-bits, Auth HMAC-SHA1 Tag 80-bits */ {"SRTP_NULL_SHA1_80", SRTP_NULL_SHA1_80, ((112 * 2) / 8)}, /* NULL Cipher, Salt:112-bits, Auth HMAC-SHA1 Tag 32-bits */ {"SRTP_NULL_SHA1_32", SRTP_NULL_SHA1_32, ((112 * 2) / 8)}, /* AES GCM 128, Salt: 96-bits, Auth GCM Tag 128-bits * (master_key:128bits + master_salt:96bits) * 2 = 448 bits (56) */ {"SRTP_AEAD_AES_128_GCM", SRTP_AEAD_AES_128_GCM, (((128 + 96) * 2) / 8) }, /* AES GCM 256, Salt: 96-bits, Auth GCM Tag 128-bits * (master_key:256bits + master_salt:96bits) * 2 = 704 bits (88) */ {"SRTP_AEAD_AES_256_GCM", SRTP_AEAD_AES_256_GCM, (((256 + 96) * 2) / 8) }, }; static const WOLFSSL_SRTP_PROTECTION_PROFILE* DtlsSrtpFindProfile( const char* profile_str, word32 profile_str_len, unsigned long id) { int i; const WOLFSSL_SRTP_PROTECTION_PROFILE* profile = NULL; for (i=0; i<(int)(sizeof(gSrtpProfiles)/sizeof(WOLFSSL_SRTP_PROTECTION_PROFILE)); i++) { if (profile_str != NULL) { word32 srtp_profile_len = (word32)XSTRLEN(gSrtpProfiles[i].name); if (srtp_profile_len == profile_str_len && XMEMCMP(gSrtpProfiles[i].name, profile_str, profile_str_len) == 0) { profile = &gSrtpProfiles[i]; break; } } else if (id != 0 && gSrtpProfiles[i].id == id) { profile = &gSrtpProfiles[i]; break; } } return profile; } /* profile_str: accepts ":" colon separated list of SRTP profiles */ static int DtlsSrtpSelProfiles(word16* id, const char* profile_str) { const WOLFSSL_SRTP_PROTECTION_PROFILE* profile; const char *current, *next = NULL; word32 length = 0, current_length; *id = 0; /* reset destination ID's */ if (profile_str == NULL) { return WOLFSSL_FAILURE; } /* loop on end of line or colon ":" */ next = profile_str; length = (word32)XSTRLEN(profile_str); do { current = next; next = XSTRSTR(current, ":"); current_length = (!next) ? (word32)XSTRLEN(current) : (word32)(next - current); if (current_length < length) length = current_length; profile = DtlsSrtpFindProfile(current, current_length, 0); if (profile != NULL) { *id |= (1 << profile->id); /* selected bit based on ID */ } } while (next != NULL && next++); /* ++ needed to skip ':' */ return WOLFSSL_SUCCESS; } int wolfSSL_CTX_set_tlsext_use_srtp(WOLFSSL_CTX* ctx, const char* profile_str) { int ret = WOLFSSL_FAILURE; if (ctx != NULL) { ret = DtlsSrtpSelProfiles(&ctx->dtlsSrtpProfiles, profile_str); } return ret; } int wolfSSL_set_tlsext_use_srtp(WOLFSSL* ssl, const char* profile_str) { int ret = WOLFSSL_FAILURE; if (ssl != NULL) { ret = DtlsSrtpSelProfiles(&ssl->dtlsSrtpProfiles, profile_str); } return ret; } const WOLFSSL_SRTP_PROTECTION_PROFILE* wolfSSL_get_selected_srtp_profile( WOLFSSL* ssl) { const WOLFSSL_SRTP_PROTECTION_PROFILE* profile = NULL; if (ssl) { profile = DtlsSrtpFindProfile(NULL, 0, ssl->dtlsSrtpId); } return profile; } #ifndef NO_WOLFSSL_STUB WOLF_STACK_OF(WOLFSSL_SRTP_PROTECTION_PROFILE)* wolfSSL_get_srtp_profiles( WOLFSSL* ssl) { /* Not yet implemented - should return list of available SRTP profiles * ssl->dtlsSrtpProfiles */ (void)ssl; return NULL; } #endif int wolfSSL_export_dtls_srtp_keying_material(WOLFSSL* ssl, unsigned char* out, size_t* olen) { int ret = WOLFSSL_FAILURE; const char* label = "EXTRACTOR-dtls_srtp"; const WOLFSSL_SRTP_PROTECTION_PROFILE* profile = NULL; byte seed[SEED_LEN]; if (ssl == NULL || olen == NULL) { return BAD_FUNC_ARG; } profile = DtlsSrtpFindProfile(NULL, 0, ssl->dtlsSrtpId); if (profile == NULL) { WOLFSSL_MSG("Not using DTLS SRTP"); return EXT_MISSING; } if (out == NULL) { *olen = profile->kdfBits; return LENGTH_ONLY_E; } if (*olen < (size_t)profile->kdfBits) { return BUFFER_E; } #ifdef WOLFSSL_HAVE_PRF XMEMCPY(seed, ssl->arrays->clientRandom, RAN_LEN); XMEMCPY(seed + RAN_LEN, ssl->arrays->serverRandom, RAN_LEN); PRIVATE_KEY_UNLOCK(); ret = wc_PRF_TLS(out, profile->kdfBits, /* out: generated keys / salt */ ssl->arrays->masterSecret, SECRET_LEN, /* existing master secret */ (const byte*)label, (int)XSTRLEN(label),/* label */ seed, SEED_LEN, /* seed: client/server random */ IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm, ssl->heap, INVALID_DEVID); if (ret == 0) { *olen = profile->kdfBits; ret = WOLFSSL_SUCCESS; } PRIVATE_KEY_LOCK(); #else /* Pseudo random function must be enabled in the configuration */ ret = PRF_MISSING; #endif return ret; } #endif /* WOLFSSL_SRTP */ #ifdef WOLFSSL_DTLS_DROP_STATS int wolfSSL_dtls_get_drop_stats(WOLFSSL* ssl, word32* macDropCount, word32* replayDropCount) { int ret; WOLFSSL_ENTER("wolfSSL_dtls_get_drop_stats()"); if (ssl == NULL) ret = BAD_FUNC_ARG; else { ret = WOLFSSL_SUCCESS; if (macDropCount != NULL) *macDropCount = ssl->macDropCount; if (replayDropCount != NULL) *replayDropCount = ssl->replayDropCount; } WOLFSSL_LEAVE("wolfSSL_dtls_get_drop_stats()", ret); return ret; } #endif /* WOLFSSL_DTLS_DROP_STATS */ #if defined(WOLFSSL_MULTICAST) int wolfSSL_CTX_mcast_set_member_id(WOLFSSL_CTX* ctx, word16 id) { int ret = 0; WOLFSSL_ENTER("wolfSSL_CTX_mcast_set_member_id()"); if (ctx == NULL || id > 255) ret = BAD_FUNC_ARG; if (ret == 0) { ctx->haveEMS = 0; ctx->haveMcast = 1; ctx->mcastID = (byte)id; #ifndef WOLFSSL_USER_IO ctx->CBIORecv = EmbedReceiveFromMcast; #endif /* WOLFSSL_USER_IO */ ret = WOLFSSL_SUCCESS; } WOLFSSL_LEAVE("wolfSSL_CTX_mcast_set_member_id()", ret); return ret; } int wolfSSL_mcast_get_max_peers(void) { return WOLFSSL_MULTICAST_PEERS; } #ifdef WOLFSSL_DTLS static WC_INLINE word32 UpdateHighwaterMark(word32 cur, word32 first, word32 second, word32 high) { word32 newCur = 0; if (cur < first) newCur = first; else if (cur < second) newCur = second; else if (cur < high) newCur = high; return newCur; } #endif /* WOLFSSL_DTLS */ int wolfSSL_set_secret(WOLFSSL* ssl, word16 epoch, const byte* preMasterSecret, word32 preMasterSz, const byte* clientRandom, const byte* serverRandom, const byte* suite) { int ret = 0; WOLFSSL_ENTER("wolfSSL_set_secret()"); if (ssl == NULL || preMasterSecret == NULL || preMasterSz == 0 || preMasterSz > ENCRYPT_LEN || clientRandom == NULL || serverRandom == NULL || suite == NULL) { ret = BAD_FUNC_ARG; } if (ret == 0 && ssl->arrays->preMasterSecret == NULL) { ssl->arrays->preMasterSz = ENCRYPT_LEN; ssl->arrays->preMasterSecret = (byte*)XMALLOC(ENCRYPT_LEN, ssl->heap, DYNAMIC_TYPE_SECRET); if (ssl->arrays->preMasterSecret == NULL) { ret = MEMORY_E; } } if (ret == 0) { XMEMCPY(ssl->arrays->preMasterSecret, preMasterSecret, preMasterSz); XMEMSET(ssl->arrays->preMasterSecret + preMasterSz, 0, ENCRYPT_LEN - preMasterSz); ssl->arrays->preMasterSz = preMasterSz; XMEMCPY(ssl->arrays->clientRandom, clientRandom, RAN_LEN); XMEMCPY(ssl->arrays->serverRandom, serverRandom, RAN_LEN); ssl->options.cipherSuite0 = suite[0]; ssl->options.cipherSuite = suite[1]; ret = SetCipherSpecs(ssl); } if (ret == 0) ret = MakeTlsMasterSecret(ssl); if (ret == 0) { ssl->keys.encryptionOn = 1; ret = SetKeysSide(ssl, ENCRYPT_AND_DECRYPT_SIDE); } if (ret == 0) { if (ssl->options.dtls) { #ifdef WOLFSSL_DTLS WOLFSSL_DTLS_PEERSEQ* peerSeq; int i; ssl->keys.dtls_epoch = epoch; for (i = 0, peerSeq = ssl->keys.peerSeq; i < WOLFSSL_DTLS_PEERSEQ_SZ; i++, peerSeq++) { peerSeq->nextEpoch = epoch; peerSeq->prevSeq_lo = peerSeq->nextSeq_lo; peerSeq->prevSeq_hi = peerSeq->nextSeq_hi; peerSeq->nextSeq_lo = 0; peerSeq->nextSeq_hi = 0; XMEMCPY(peerSeq->prevWindow, peerSeq->window, DTLS_SEQ_SZ); XMEMSET(peerSeq->window, 0, DTLS_SEQ_SZ); peerSeq->highwaterMark = UpdateHighwaterMark(0, ssl->ctx->mcastFirstSeq, ssl->ctx->mcastSecondSeq, ssl->ctx->mcastMaxSeq); } #else (void)epoch; #endif } FreeHandshakeResources(ssl); ret = WOLFSSL_SUCCESS; } else { if (ssl) ssl->error = ret; ret = WOLFSSL_FATAL_ERROR; } WOLFSSL_LEAVE("wolfSSL_set_secret()", ret); return ret; } #ifdef WOLFSSL_DTLS int wolfSSL_mcast_peer_add(WOLFSSL* ssl, word16 peerId, int sub) { WOLFSSL_DTLS_PEERSEQ* p = NULL; int ret = WOLFSSL_SUCCESS; int i; WOLFSSL_ENTER("wolfSSL_mcast_peer_add()"); if (ssl == NULL || peerId > 255) return BAD_FUNC_ARG; if (!sub) { /* Make sure it isn't already present, while keeping the first * open spot. */ for (i = 0; i < WOLFSSL_DTLS_PEERSEQ_SZ; i++) { if (ssl->keys.peerSeq[i].peerId == INVALID_PEER_ID) p = &ssl->keys.peerSeq[i]; if (ssl->keys.peerSeq[i].peerId == peerId) { WOLFSSL_MSG("Peer ID already in multicast peer list."); p = NULL; } } if (p != NULL) { XMEMSET(p, 0, sizeof(WOLFSSL_DTLS_PEERSEQ)); p->peerId = peerId; p->highwaterMark = UpdateHighwaterMark(0, ssl->ctx->mcastFirstSeq, ssl->ctx->mcastSecondSeq, ssl->ctx->mcastMaxSeq); } else { WOLFSSL_MSG("No room in peer list."); ret = -1; } } else { for (i = 0; i < WOLFSSL_DTLS_PEERSEQ_SZ; i++) { if (ssl->keys.peerSeq[i].peerId == peerId) p = &ssl->keys.peerSeq[i]; } if (p != NULL) { p->peerId = INVALID_PEER_ID; } else { WOLFSSL_MSG("Peer not found in list."); } } WOLFSSL_LEAVE("wolfSSL_mcast_peer_add()", ret); return ret; } /* If peerId is in the list of peers and its last sequence number is non-zero, * return 1, otherwise return 0. */ int wolfSSL_mcast_peer_known(WOLFSSL* ssl, unsigned short peerId) { int known = 0; int i; WOLFSSL_ENTER("wolfSSL_mcast_peer_known()"); if (ssl == NULL || peerId > 255) { return BAD_FUNC_ARG; } for (i = 0; i < WOLFSSL_DTLS_PEERSEQ_SZ; i++) { if (ssl->keys.peerSeq[i].peerId == peerId) { if (ssl->keys.peerSeq[i].nextSeq_hi || ssl->keys.peerSeq[i].nextSeq_lo) { known = 1; } break; } } WOLFSSL_LEAVE("wolfSSL_mcast_peer_known()", known); return known; } int wolfSSL_CTX_mcast_set_highwater_cb(WOLFSSL_CTX* ctx, word32 maxSeq, word32 first, word32 second, CallbackMcastHighwater cb) { if (ctx == NULL || (second && first > second) || first > maxSeq || second > maxSeq || cb == NULL) { return BAD_FUNC_ARG; } ctx->mcastHwCb = cb; ctx->mcastFirstSeq = first; ctx->mcastSecondSeq = second; ctx->mcastMaxSeq = maxSeq; return WOLFSSL_SUCCESS; } int wolfSSL_mcast_set_highwater_ctx(WOLFSSL* ssl, void* ctx) { if (ssl == NULL || ctx == NULL) return BAD_FUNC_ARG; ssl->mcastHwCbCtx = ctx; return WOLFSSL_SUCCESS; } #endif /* WOLFSSL_DTLS */ #endif /* WOLFSSL_MULTICAST */ #endif /* WOLFSSL_LEANPSK */ /* return underlying connect or accept, WOLFSSL_SUCCESS on ok */ int wolfSSL_negotiate(WOLFSSL* ssl) { int err = WOLFSSL_FATAL_ERROR; WOLFSSL_ENTER("wolfSSL_negotiate"); #ifndef NO_WOLFSSL_SERVER if (ssl->options.side == WOLFSSL_SERVER_END) { #ifdef WOLFSSL_TLS13 if (IsAtLeastTLSv1_3(ssl->version)) err = wolfSSL_accept_TLSv13(ssl); else #endif err = wolfSSL_accept(ssl); } #endif #ifndef NO_WOLFSSL_CLIENT if (ssl->options.side == WOLFSSL_CLIENT_END) { #ifdef WOLFSSL_TLS13 if (IsAtLeastTLSv1_3(ssl->version)) err = wolfSSL_connect_TLSv13(ssl); else #endif err = wolfSSL_connect(ssl); } #endif (void)ssl; WOLFSSL_LEAVE("wolfSSL_negotiate", err); return err; } WOLFSSL_ABI WC_RNG* wolfSSL_GetRNG(WOLFSSL* ssl) { if (ssl) { return ssl->rng; } return NULL; } #ifndef WOLFSSL_LEANPSK /* object size based on build */ int wolfSSL_GetObjectSize(void) { #ifdef SHOW_SIZES printf("sizeof suites = %lu\n", (unsigned long)sizeof(Suites)); printf("sizeof ciphers(2) = %lu\n", (unsigned long)sizeof(Ciphers)); #ifndef NO_RC4 printf("\tsizeof arc4 = %lu\n", (unsigned long)sizeof(Arc4)); #endif printf("\tsizeof aes = %lu\n", (unsigned long)sizeof(Aes)); #ifndef NO_DES3 printf("\tsizeof des3 = %lu\n", (unsigned long)sizeof(Des3)); #endif #ifdef HAVE_CHACHA printf("\tsizeof chacha = %lu\n", (unsigned long)sizeof(ChaCha)); #endif printf("sizeof cipher specs = %lu\n", (unsigned long)sizeof(CipherSpecs)); printf("sizeof keys = %lu\n", (unsigned long)sizeof(Keys)); printf("sizeof Hashes(2) = %lu\n", (unsigned long)sizeof(Hashes)); #ifndef NO_MD5 printf("\tsizeof MD5 = %lu\n", (unsigned long)sizeof(wc_Md5)); #endif #ifndef NO_SHA printf("\tsizeof SHA = %lu\n", (unsigned long)sizeof(wc_Sha)); #endif #ifdef WOLFSSL_SHA224 printf("\tsizeof SHA224 = %lu\n", (unsigned long)sizeof(wc_Sha224)); #endif #ifndef NO_SHA256 printf("\tsizeof SHA256 = %lu\n", (unsigned long)sizeof(wc_Sha256)); #endif #ifdef WOLFSSL_SHA384 printf("\tsizeof SHA384 = %lu\n", (unsigned long)sizeof(wc_Sha384)); #endif #ifdef WOLFSSL_SHA384 printf("\tsizeof SHA512 = %lu\n", (unsigned long)sizeof(wc_Sha512)); #endif printf("sizeof Buffers = %lu\n", (unsigned long)sizeof(Buffers)); printf("sizeof Options = %lu\n", (unsigned long)sizeof(Options)); printf("sizeof Arrays = %lu\n", (unsigned long)sizeof(Arrays)); #ifndef NO_RSA printf("sizeof RsaKey = %lu\n", (unsigned long)sizeof(RsaKey)); #endif #ifdef HAVE_ECC printf("sizeof ecc_key = %lu\n", (unsigned long)sizeof(ecc_key)); #endif printf("sizeof WOLFSSL_CIPHER = %lu\n", (unsigned long)sizeof(WOLFSSL_CIPHER)); printf("sizeof WOLFSSL_SESSION = %lu\n", (unsigned long)sizeof(WOLFSSL_SESSION)); printf("sizeof WOLFSSL = %lu\n", (unsigned long)sizeof(WOLFSSL)); printf("sizeof WOLFSSL_CTX = %lu\n", (unsigned long)sizeof(WOLFSSL_CTX)); #endif return sizeof(WOLFSSL); } int wolfSSL_CTX_GetObjectSize(void) { return sizeof(WOLFSSL_CTX); } int wolfSSL_METHOD_GetObjectSize(void) { return sizeof(WOLFSSL_METHOD); } #endif #ifdef WOLFSSL_STATIC_MEMORY int wolfSSL_CTX_load_static_memory(WOLFSSL_CTX** ctx, wolfSSL_method_func method, unsigned char* buf, unsigned int sz, int flag, int maxSz) { WOLFSSL_HEAP* heap; WOLFSSL_HEAP_HINT* hint; word32 idx = 0; if (ctx == NULL || buf == NULL) { return BAD_FUNC_ARG; } if (*ctx == NULL && method == NULL) { return BAD_FUNC_ARG; } if (*ctx == NULL || (*ctx)->heap == NULL) { if (sizeof(WOLFSSL_HEAP) + sizeof(WOLFSSL_HEAP_HINT) > sz - idx) { return BUFFER_E; /* not enough memory for structures */ } heap = (WOLFSSL_HEAP*)buf; idx += sizeof(WOLFSSL_HEAP); if (wolfSSL_init_memory_heap(heap) != 0) { return WOLFSSL_FAILURE; } hint = (WOLFSSL_HEAP_HINT*)(buf + idx); idx += sizeof(WOLFSSL_HEAP_HINT); XMEMSET(hint, 0, sizeof(WOLFSSL_HEAP_HINT)); hint->memory = heap; if (*ctx && (*ctx)->heap == NULL) { (*ctx)->heap = (void*)hint; } } else { #ifdef WOLFSSL_HEAP_TEST /* do not load in memory if test has been set */ if ((*ctx)->heap == (void*)WOLFSSL_HEAP_TEST) { return WOLFSSL_SUCCESS; } #endif hint = (WOLFSSL_HEAP_HINT*)((*ctx)->heap); heap = hint->memory; } if (wolfSSL_load_static_memory(buf + idx, sz - idx, flag, heap) != 1) { WOLFSSL_MSG("Error partitioning memory"); return WOLFSSL_FAILURE; } /* create ctx if needed */ if (*ctx == NULL) { *ctx = wolfSSL_CTX_new_ex(method(hint), hint); if (*ctx == NULL) { WOLFSSL_MSG("Error creating ctx"); return WOLFSSL_FAILURE; } } /* determine what max applies too */ if (flag & WOLFMEM_IO_POOL || flag & WOLFMEM_IO_POOL_FIXED) { heap->maxIO = maxSz; } else { /* general memory used in handshakes */ heap->maxHa = maxSz; } heap->flag |= flag; (void)maxSz; (void)method; return WOLFSSL_SUCCESS; } int wolfSSL_is_static_memory(WOLFSSL* ssl, WOLFSSL_MEM_CONN_STATS* mem_stats) { if (ssl == NULL) { return BAD_FUNC_ARG; } WOLFSSL_ENTER("wolfSSL_is_static_memory"); /* fill out statistics if wanted and WOLFMEM_TRACK_STATS flag */ if (mem_stats != NULL && ssl->heap != NULL) { WOLFSSL_HEAP_HINT* hint = ((WOLFSSL_HEAP_HINT*)(ssl->heap)); WOLFSSL_HEAP* heap = hint->memory; if (heap->flag & WOLFMEM_TRACK_STATS && hint->stats != NULL) { XMEMCPY(mem_stats, hint->stats, sizeof(WOLFSSL_MEM_CONN_STATS)); } } return (ssl->heap) ? 1 : 0; } int wolfSSL_CTX_is_static_memory(WOLFSSL_CTX* ctx, WOLFSSL_MEM_STATS* mem_stats) { if (ctx == NULL) { return BAD_FUNC_ARG; } WOLFSSL_ENTER("wolfSSL_CTX_is_static_memory"); /* fill out statistics if wanted */ if (mem_stats != NULL && ctx->heap != NULL) { WOLFSSL_HEAP* heap = ((WOLFSSL_HEAP_HINT*)(ctx->heap))->memory; if (wolfSSL_GetMemStats(heap, mem_stats) != 1) { return MEMORY_E; } } return (ctx->heap) ? 1 : 0; } #endif /* WOLFSSL_STATIC_MEMORY */ /* return max record layer size plaintext input size */ int wolfSSL_GetMaxOutputSize(WOLFSSL* ssl) { WOLFSSL_ENTER("wolfSSL_GetMaxOutputSize"); if (ssl == NULL) return BAD_FUNC_ARG; if (ssl->options.handShakeState != HANDSHAKE_DONE) { WOLFSSL_MSG("Handshake not complete yet"); return BAD_FUNC_ARG; } return wolfSSL_GetMaxFragSize(ssl, OUTPUT_RECORD_SIZE); } /* return record layer size of plaintext input size */ int wolfSSL_GetOutputSize(WOLFSSL* ssl, int inSz) { int maxSize; WOLFSSL_ENTER("wolfSSL_GetOutputSize"); if (inSz < 0) return BAD_FUNC_ARG; maxSize = wolfSSL_GetMaxOutputSize(ssl); if (maxSize < 0) return maxSize; /* error */ if (inSz > maxSize) return INPUT_SIZE_E; return BuildMessage(ssl, NULL, 0, NULL, inSz, application_data, 0, 1, 0, CUR_ORDER); } #ifdef HAVE_ECC int wolfSSL_CTX_SetMinEccKey_Sz(WOLFSSL_CTX* ctx, short keySz) { if (ctx == NULL || keySz < 0 || keySz % 8 != 0) { WOLFSSL_MSG("Key size must be divisible by 8 or ctx was null"); return BAD_FUNC_ARG; } ctx->minEccKeySz = keySz / 8; #ifndef NO_CERTS ctx->cm->minEccKeySz = keySz / 8; #endif return WOLFSSL_SUCCESS; } int wolfSSL_SetMinEccKey_Sz(WOLFSSL* ssl, short keySz) { if (ssl == NULL || keySz < 0 || keySz % 8 != 0) { WOLFSSL_MSG("Key size must be divisible by 8 or ssl was null"); return BAD_FUNC_ARG; } ssl->options.minEccKeySz = keySz / 8; return WOLFSSL_SUCCESS; } #endif /* HAVE_ECC */ #ifndef NO_RSA int wolfSSL_CTX_SetMinRsaKey_Sz(WOLFSSL_CTX* ctx, short keySz) { if (ctx == NULL || keySz < 0 || keySz % 8 != 0) { WOLFSSL_MSG("Key size must be divisible by 8 or ctx was null"); return BAD_FUNC_ARG; } ctx->minRsaKeySz = keySz / 8; ctx->cm->minRsaKeySz = keySz / 8; return WOLFSSL_SUCCESS; } int wolfSSL_SetMinRsaKey_Sz(WOLFSSL* ssl, short keySz) { if (ssl == NULL || keySz < 0 || keySz % 8 != 0) { WOLFSSL_MSG("Key size must be divisible by 8 or ssl was null"); return BAD_FUNC_ARG; } ssl->options.minRsaKeySz = keySz / 8; return WOLFSSL_SUCCESS; } #endif /* !NO_RSA */ #ifndef NO_DH /* server Diffie-Hellman parameters, WOLFSSL_SUCCESS on ok */ int wolfSSL_SetTmpDH(WOLFSSL* ssl, const unsigned char* p, int pSz, const unsigned char* g, int gSz) { WOLFSSL_ENTER("wolfSSL_SetTmpDH"); if (ssl == NULL || p == NULL || g == NULL) return BAD_FUNC_ARG; if ((word16)pSz < ssl->options.minDhKeySz) return DH_KEY_SIZE_E; if ((word16)pSz > ssl->options.maxDhKeySz) return DH_KEY_SIZE_E; /* this function is for server only */ if (ssl->options.side == WOLFSSL_CLIENT_END) return SIDE_ERROR; #if !defined(WOLFSSL_OLD_PRIME_CHECK) && !defined(HAVE_FIPS) && \ !defined(HAVE_SELFTEST) ssl->options.dhKeyTested = 0; ssl->options.dhDoKeyTest = 1; #endif if (ssl->buffers.serverDH_P.buffer && ssl->buffers.weOwnDH) { XFREE(ssl->buffers.serverDH_P.buffer, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); ssl->buffers.serverDH_P.buffer = NULL; } if (ssl->buffers.serverDH_G.buffer && ssl->buffers.weOwnDH) { XFREE(ssl->buffers.serverDH_G.buffer, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); ssl->buffers.serverDH_G.buffer = NULL; } ssl->buffers.weOwnDH = 1; /* SSL owns now */ ssl->buffers.serverDH_P.buffer = (byte*)XMALLOC(pSz, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); if (ssl->buffers.serverDH_P.buffer == NULL) return MEMORY_E; ssl->buffers.serverDH_G.buffer = (byte*)XMALLOC(gSz, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); if (ssl->buffers.serverDH_G.buffer == NULL) { XFREE(ssl->buffers.serverDH_P.buffer, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); ssl->buffers.serverDH_P.buffer = NULL; return MEMORY_E; } ssl->buffers.serverDH_P.length = pSz; ssl->buffers.serverDH_G.length = gSz; XMEMCPY(ssl->buffers.serverDH_P.buffer, p, pSz); XMEMCPY(ssl->buffers.serverDH_G.buffer, g, gSz); ssl->options.haveDH = 1; if (ssl->options.side != WOLFSSL_NEITHER_END) { word16 havePSK; word16 haveRSA; int keySz = 0; #ifndef NO_PSK havePSK = ssl->options.havePSK; #else havePSK = 0; #endif #ifdef NO_RSA haveRSA = 0; #else haveRSA = 1; #endif #ifndef NO_CERTS keySz = ssl->buffers.keySz; #endif InitSuites(ssl->suites, ssl->version, keySz, haveRSA, havePSK, ssl->options.haveDH, ssl->options.haveECDSAsig, ssl->options.haveECC, ssl->options.haveStaticECC, ssl->options.haveFalconSig, ssl->options.haveAnon, ssl->options.side); } WOLFSSL_LEAVE("wolfSSL_SetTmpDH", 0); return WOLFSSL_SUCCESS; } #if !defined(WOLFSSL_OLD_PRIME_CHECK) && !defined(HAVE_FIPS) && \ !defined(HAVE_SELFTEST) /* Enables or disables the session's DH key prime test. */ int wolfSSL_SetEnableDhKeyTest(WOLFSSL* ssl, int enable) { WOLFSSL_ENTER("wolfSSL_SetEnableDhKeyTest"); if (ssl == NULL) return BAD_FUNC_ARG; if (!enable) ssl->options.dhDoKeyTest = 0; else ssl->options.dhDoKeyTest = 1; WOLFSSL_LEAVE("wolfSSL_SetEnableDhKeyTest", WOLFSSL_SUCCESS); return WOLFSSL_SUCCESS; } #endif /* server ctx Diffie-Hellman parameters, WOLFSSL_SUCCESS on ok */ int wolfSSL_CTX_SetTmpDH(WOLFSSL_CTX* ctx, const unsigned char* p, int pSz, const unsigned char* g, int gSz) { WOLFSSL_ENTER("wolfSSL_CTX_SetTmpDH"); if (ctx == NULL || p == NULL || g == NULL) return BAD_FUNC_ARG; if ((word16)pSz < ctx->minDhKeySz) return DH_KEY_SIZE_E; if ((word16)pSz > ctx->maxDhKeySz) return DH_KEY_SIZE_E; #if !defined(WOLFSSL_OLD_PRIME_CHECK) && !defined(HAVE_FIPS) && \ !defined(HAVE_SELFTEST) { WC_RNG rng; int error, freeKey = 0; #ifdef WOLFSSL_SMALL_STACK DhKey *checkKey = (DhKey*)XMALLOC(sizeof(DhKey), NULL, DYNAMIC_TYPE_DH); if (checkKey == NULL) return MEMORY_E; #else DhKey checkKey[1]; #endif error = wc_InitRng(&rng); if (!error) error = wc_InitDhKey(checkKey); if (!error) { freeKey = 1; error = wc_DhSetCheckKey(checkKey, p, pSz, g, gSz, NULL, 0, 0, &rng); } if (freeKey) wc_FreeDhKey(checkKey); #ifdef WOLFSSL_SMALL_STACK XFREE(checkKey, NULL, DYNAMIC_TYPE_DH); #endif wc_FreeRng(&rng); if (error) return error; ctx->dhKeyTested = 1; } #endif XFREE(ctx->serverDH_P.buffer, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); ctx->serverDH_P.buffer = NULL; XFREE(ctx->serverDH_G.buffer, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); ctx->serverDH_G.buffer = NULL; ctx->serverDH_P.buffer = (byte*)XMALLOC(pSz, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); if (ctx->serverDH_P.buffer == NULL) return MEMORY_E; ctx->serverDH_G.buffer = (byte*)XMALLOC(gSz, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); if (ctx->serverDH_G.buffer == NULL) { XFREE(ctx->serverDH_P.buffer, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); ctx->serverDH_P.buffer = NULL; return MEMORY_E; } ctx->serverDH_P.length = pSz; ctx->serverDH_G.length = gSz; XMEMCPY(ctx->serverDH_P.buffer, p, pSz); XMEMCPY(ctx->serverDH_G.buffer, g, gSz); ctx->haveDH = 1; WOLFSSL_LEAVE("wolfSSL_CTX_SetTmpDH", 0); return WOLFSSL_SUCCESS; } int wolfSSL_CTX_SetMinDhKey_Sz(WOLFSSL_CTX* ctx, word16 keySz_bits) { if (ctx == NULL || keySz_bits > 16000 || keySz_bits % 8 != 0) return BAD_FUNC_ARG; ctx->minDhKeySz = keySz_bits / 8; return WOLFSSL_SUCCESS; } int wolfSSL_SetMinDhKey_Sz(WOLFSSL* ssl, word16 keySz_bits) { if (ssl == NULL || keySz_bits > 16000 || keySz_bits % 8 != 0) return BAD_FUNC_ARG; ssl->options.minDhKeySz = keySz_bits / 8; return WOLFSSL_SUCCESS; } int wolfSSL_CTX_SetMaxDhKey_Sz(WOLFSSL_CTX* ctx, word16 keySz_bits) { if (ctx == NULL || keySz_bits > 16000 || keySz_bits % 8 != 0) return BAD_FUNC_ARG; ctx->maxDhKeySz = keySz_bits / 8; return WOLFSSL_SUCCESS; } int wolfSSL_SetMaxDhKey_Sz(WOLFSSL* ssl, word16 keySz_bits) { if (ssl == NULL || keySz_bits > 16000 || keySz_bits % 8 != 0) return BAD_FUNC_ARG; ssl->options.maxDhKeySz = keySz_bits / 8; return WOLFSSL_SUCCESS; } int wolfSSL_GetDhKey_Sz(WOLFSSL* ssl) { if (ssl == NULL) return BAD_FUNC_ARG; return (ssl->options.dhKeySz * 8); } #endif /* !NO_DH */ WOLFSSL_ABI int wolfSSL_write(WOLFSSL* ssl, const void* data, int sz) { int ret; WOLFSSL_ENTER("SSL_write()"); if (ssl == NULL || data == NULL || sz < 0) return BAD_FUNC_ARG; #ifdef WOLFSSL_EARLY_DATA if (ssl->earlyData != no_early_data && (ret = wolfSSL_negotiate(ssl)) < 0) { ssl->error = ret; return WOLFSSL_FATAL_ERROR; } ssl->earlyData = no_early_data; #endif #ifdef HAVE_WRITE_DUP { /* local variable scope */ int dupErr = 0; /* local copy */ ret = 0; if (ssl->dupWrite && ssl->dupSide == READ_DUP_SIDE) { WOLFSSL_MSG("Read dup side cannot write"); return WRITE_DUP_WRITE_E; } if (ssl->dupWrite) { if (wc_LockMutex(&ssl->dupWrite->dupMutex) != 0) { return BAD_MUTEX_E; } dupErr = ssl->dupWrite->dupErr; ret = wc_UnLockMutex(&ssl->dupWrite->dupMutex); } if (ret != 0) { ssl->error = ret; /* high priority fatal error */ return WOLFSSL_FATAL_ERROR; } if (dupErr != 0) { WOLFSSL_MSG("Write dup error from other side"); ssl->error = dupErr; return WOLFSSL_FATAL_ERROR; } } #endif #ifdef HAVE_ERRNO_H errno = 0; #endif #ifdef OPENSSL_EXTRA if (ssl->CBIS != NULL) { ssl->CBIS(ssl, SSL_CB_WRITE, WOLFSSL_SUCCESS); ssl->cbmode = SSL_CB_WRITE; } #endif ret = SendData(ssl, data, sz); WOLFSSL_LEAVE("SSL_write()", ret); if (ret < 0) return WOLFSSL_FATAL_ERROR; else return ret; } static int wolfSSL_read_internal(WOLFSSL* ssl, void* data, int sz, int peek) { int ret; WOLFSSL_ENTER("wolfSSL_read_internal()"); if (ssl == NULL || data == NULL || sz < 0) return BAD_FUNC_ARG; #if defined(WOLFSSL_ERROR_CODE_OPENSSL) && defined(OPENSSL_EXTRA) /* This additional logic is meant to simulate following openSSL behavior: * After bidirectional SSL_shutdown complete, SSL_read returns 0 and * SSL_get_error_code returns SSL_ERROR_ZERO_RETURN. * This behavior is used to know the disconnect of the underlying * transport layer. * * In this logic, CBIORecv is called with a read size of 0 to check the * transport layer status. It also returns WOLFSSL_FAILURE so that * SSL_read does not return a positive number on failure. */ /* make sure bidirectional TLS shutdown completes */ if (ssl->error == WOLFSSL_ERROR_SYSCALL) { /* ask the underlying transport the connection is closed */ if (ssl->CBIORecv(ssl, (char*)data, 0, ssl->IOCB_ReadCtx) == WOLFSSL_CBIO_ERR_CONN_CLOSE) { ssl->options.isClosed = 1; ssl->error = WOLFSSL_ERROR_ZERO_RETURN; } return WOLFSSL_FAILURE; } #endif #ifdef HAVE_WRITE_DUP if (ssl->dupWrite && ssl->dupSide == WRITE_DUP_SIDE) { WOLFSSL_MSG("Write dup side cannot read"); return WRITE_DUP_READ_E; } #endif #ifdef HAVE_ERRNO_H errno = 0; #endif #ifdef WOLFSSL_DTLS if (ssl->options.dtls) { ssl->dtls_expected_rx = max(sz + DTLS_MTU_ADDITIONAL_READ_BUFFER, MAX_MTU); #ifdef WOLFSSL_SCTP if (ssl->options.dtlsSctp) #endif #if defined(WOLFSSL_SCTP) || defined(WOLFSSL_DTLS_MTU) /* Add some bytes so that we can operate with slight difference * in set MTU size on each peer */ ssl->dtls_expected_rx = max(ssl->dtls_expected_rx, ssl->dtlsMtuSz + (word32)DTLS_MTU_ADDITIONAL_READ_BUFFER); #endif } #endif ret = ReceiveData(ssl, (byte*)data, sz, peek); #ifdef HAVE_WRITE_DUP if (ssl->dupWrite) { if (ssl->error != 0 && ssl->error != WANT_READ #ifdef WOLFSSL_ASYNC_CRYPT && ssl->error != WC_PENDING_E #endif ) { int notifyErr; WOLFSSL_MSG("Notifying write side of fatal read error"); notifyErr = NotifyWriteSide(ssl, ssl->error); if (notifyErr < 0) { ret = ssl->error = notifyErr; } } } #endif WOLFSSL_LEAVE("wolfSSL_read_internal()", ret); if (ret < 0) return WOLFSSL_FATAL_ERROR; else return ret; } int wolfSSL_peek(WOLFSSL* ssl, void* data, int sz) { WOLFSSL_ENTER("wolfSSL_peek()"); return wolfSSL_read_internal(ssl, data, sz, TRUE); } WOLFSSL_ABI int wolfSSL_read(WOLFSSL* ssl, void* data, int sz) { WOLFSSL_ENTER("wolfSSL_read()"); #ifdef OPENSSL_EXTRA if (ssl == NULL) { return BAD_FUNC_ARG; } if (ssl->CBIS != NULL) { ssl->CBIS(ssl, SSL_CB_READ, WOLFSSL_SUCCESS); ssl->cbmode = SSL_CB_READ; } #endif return wolfSSL_read_internal(ssl, data, sz, FALSE); } #ifdef WOLFSSL_MULTICAST int wolfSSL_mcast_read(WOLFSSL* ssl, word16* id, void* data, int sz) { int ret = 0; WOLFSSL_ENTER("wolfSSL_mcast_read()"); if (ssl == NULL) return BAD_FUNC_ARG; ret = wolfSSL_read_internal(ssl, data, sz, FALSE); if (ssl->options.dtls && ssl->options.haveMcast && id != NULL) *id = ssl->keys.curPeerId; return ret; } #endif /* WOLFSSL_MULTICAST */ /* helpers to set the device id, WOLFSSL_SUCCESS on ok */ WOLFSSL_ABI int wolfSSL_SetDevId(WOLFSSL* ssl, int devId) { if (ssl == NULL) return BAD_FUNC_ARG; ssl->devId = devId; return WOLFSSL_SUCCESS; } WOLFSSL_ABI int wolfSSL_CTX_SetDevId(WOLFSSL_CTX* ctx, int devId) { if (ctx == NULL) return BAD_FUNC_ARG; ctx->devId = devId; return WOLFSSL_SUCCESS; } /* helpers to get device id and heap */ WOLFSSL_ABI int wolfSSL_CTX_GetDevId(WOLFSSL_CTX* ctx, WOLFSSL* ssl) { int devId = INVALID_DEVID; if (ssl != NULL) devId = ssl->devId; if (ctx != NULL && devId == INVALID_DEVID) devId = ctx->devId; return devId; } void* wolfSSL_CTX_GetHeap(WOLFSSL_CTX* ctx, WOLFSSL* ssl) { void* heap = NULL; if (ctx != NULL) heap = ctx->heap; else if (ssl != NULL) heap = ssl->heap; return heap; } #ifdef HAVE_SNI WOLFSSL_ABI int wolfSSL_UseSNI(WOLFSSL* ssl, byte type, const void* data, word16 size) { if (ssl == NULL) return BAD_FUNC_ARG; return TLSX_UseSNI(&ssl->extensions, type, data, size, ssl->heap); } WOLFSSL_ABI int wolfSSL_CTX_UseSNI(WOLFSSL_CTX* ctx, byte type, const void* data, word16 size) { if (ctx == NULL) return BAD_FUNC_ARG; return TLSX_UseSNI(&ctx->extensions, type, data, size, ctx->heap); } #ifndef NO_WOLFSSL_SERVER void wolfSSL_SNI_SetOptions(WOLFSSL* ssl, byte type, byte options) { if (ssl && ssl->extensions) TLSX_SNI_SetOptions(ssl->extensions, type, options); } void wolfSSL_CTX_SNI_SetOptions(WOLFSSL_CTX* ctx, byte type, byte options) { if (ctx && ctx->extensions) TLSX_SNI_SetOptions(ctx->extensions, type, options); } byte wolfSSL_SNI_Status(WOLFSSL* ssl, byte type) { return TLSX_SNI_Status(ssl ? ssl->extensions : NULL, type); } word16 wolfSSL_SNI_GetRequest(WOLFSSL* ssl, byte type, void** data) { if (data) *data = NULL; if (ssl && ssl->extensions) return TLSX_SNI_GetRequest(ssl->extensions, type, data); return 0; } int wolfSSL_SNI_GetFromBuffer(const byte* clientHello, word32 helloSz, byte type, byte* sni, word32* inOutSz) { if (clientHello && helloSz > 0 && sni && inOutSz && *inOutSz > 0) return TLSX_SNI_GetFromBuffer(clientHello, helloSz, type, sni, inOutSz); return BAD_FUNC_ARG; } #endif /* NO_WOLFSSL_SERVER */ #endif /* HAVE_SNI */ #ifdef HAVE_TRUSTED_CA WOLFSSL_API int wolfSSL_UseTrustedCA(WOLFSSL* ssl, byte type, const byte* certId, word32 certIdSz) { if (ssl == NULL) return BAD_FUNC_ARG; if (type == WOLFSSL_TRUSTED_CA_PRE_AGREED) { if (certId != NULL || certIdSz != 0) return BAD_FUNC_ARG; } else if (type == WOLFSSL_TRUSTED_CA_X509_NAME) { if (certId == NULL || certIdSz == 0) return BAD_FUNC_ARG; } #ifndef NO_SHA else if (type == WOLFSSL_TRUSTED_CA_KEY_SHA1 || type == WOLFSSL_TRUSTED_CA_CERT_SHA1) { if (certId == NULL || certIdSz != WC_SHA_DIGEST_SIZE) return BAD_FUNC_ARG; } #endif else return BAD_FUNC_ARG; return TLSX_UseTrustedCA(&ssl->extensions, type, certId, certIdSz, ssl->heap); } #endif /* HAVE_TRUSTED_CA */ #ifdef HAVE_MAX_FRAGMENT #ifndef NO_WOLFSSL_CLIENT int wolfSSL_UseMaxFragment(WOLFSSL* ssl, byte mfl) { if (ssl == NULL) return BAD_FUNC_ARG; #ifdef WOLFSSL_ALLOW_MAX_FRAGMENT_ADJUST /* The following is a non-standard way to reconfigure the max packet size post-handshake for wolfSSL_write/wolfSSL_read */ if (ssl->options.handShakeState == HANDSHAKE_DONE) { switch (mfl) { case WOLFSSL_MFL_2_8 : ssl->max_fragment = 256; break; case WOLFSSL_MFL_2_9 : ssl->max_fragment = 512; break; case WOLFSSL_MFL_2_10: ssl->max_fragment = 1024; break; case WOLFSSL_MFL_2_11: ssl->max_fragment = 2048; break; case WOLFSSL_MFL_2_12: ssl->max_fragment = 4096; break; case WOLFSSL_MFL_2_13: ssl->max_fragment = 8192; break; default: ssl->max_fragment = MAX_RECORD_SIZE; break; } return WOLFSSL_SUCCESS; } #endif /* WOLFSSL_MAX_FRAGMENT_ADJUST */ /* This call sets the max fragment TLS extension, which gets sent to server. The server_hello response is what sets the `ssl->max_fragment` in TLSX_MFL_Parse */ return TLSX_UseMaxFragment(&ssl->extensions, mfl, ssl->heap); } int wolfSSL_CTX_UseMaxFragment(WOLFSSL_CTX* ctx, byte mfl) { if (ctx == NULL) return BAD_FUNC_ARG; return TLSX_UseMaxFragment(&ctx->extensions, mfl, ctx->heap); } #endif /* NO_WOLFSSL_CLIENT */ #endif /* HAVE_MAX_FRAGMENT */ #ifdef HAVE_TRUNCATED_HMAC #ifndef NO_WOLFSSL_CLIENT int wolfSSL_UseTruncatedHMAC(WOLFSSL* ssl) { if (ssl == NULL) return BAD_FUNC_ARG; return TLSX_UseTruncatedHMAC(&ssl->extensions, ssl->heap); } int wolfSSL_CTX_UseTruncatedHMAC(WOLFSSL_CTX* ctx) { if (ctx == NULL) return BAD_FUNC_ARG; return TLSX_UseTruncatedHMAC(&ctx->extensions, ctx->heap); } #endif /* NO_WOLFSSL_CLIENT */ #endif /* HAVE_TRUNCATED_HMAC */ #ifdef HAVE_CERTIFICATE_STATUS_REQUEST int wolfSSL_UseOCSPStapling(WOLFSSL* ssl, byte status_type, byte options) { WOLFSSL_ENTER("wolfSSL_UseOCSPStapling"); if (ssl == NULL || ssl->options.side != WOLFSSL_CLIENT_END) return BAD_FUNC_ARG; return TLSX_UseCertificateStatusRequest(&ssl->extensions, status_type, options, NULL, ssl->heap, ssl->devId); } int wolfSSL_CTX_UseOCSPStapling(WOLFSSL_CTX* ctx, byte status_type, byte options) { WOLFSSL_ENTER("wolfSSL_CTX_UseOCSPStapling"); if (ctx == NULL || ctx->method->side != WOLFSSL_CLIENT_END) return BAD_FUNC_ARG; return TLSX_UseCertificateStatusRequest(&ctx->extensions, status_type, options, NULL, ctx->heap, ctx->devId); } #endif /* HAVE_CERTIFICATE_STATUS_REQUEST */ #ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2 int wolfSSL_UseOCSPStaplingV2(WOLFSSL* ssl, byte status_type, byte options) { if (ssl == NULL || ssl->options.side != WOLFSSL_CLIENT_END) return BAD_FUNC_ARG; return TLSX_UseCertificateStatusRequestV2(&ssl->extensions, status_type, options, ssl->heap, ssl->devId); } int wolfSSL_CTX_UseOCSPStaplingV2(WOLFSSL_CTX* ctx, byte status_type, byte options) { if (ctx == NULL || ctx->method->side != WOLFSSL_CLIENT_END) return BAD_FUNC_ARG; return TLSX_UseCertificateStatusRequestV2(&ctx->extensions, status_type, options, ctx->heap, ctx->devId); } #endif /* HAVE_CERTIFICATE_STATUS_REQUEST_V2 */ /* Elliptic Curves */ #if defined(HAVE_SUPPORTED_CURVES) static int isValidCurveGroup(word16 name) { switch (name) { case WOLFSSL_ECC_SECP160K1: case WOLFSSL_ECC_SECP160R1: case WOLFSSL_ECC_SECP160R2: case WOLFSSL_ECC_SECP192K1: case WOLFSSL_ECC_SECP192R1: case WOLFSSL_ECC_SECP224K1: case WOLFSSL_ECC_SECP224R1: case WOLFSSL_ECC_SECP256K1: case WOLFSSL_ECC_SECP256R1: case WOLFSSL_ECC_SECP384R1: case WOLFSSL_ECC_SECP521R1: case WOLFSSL_ECC_BRAINPOOLP256R1: case WOLFSSL_ECC_BRAINPOOLP384R1: case WOLFSSL_ECC_BRAINPOOLP512R1: case WOLFSSL_ECC_X25519: case WOLFSSL_ECC_X448: case WOLFSSL_FFDHE_2048: case WOLFSSL_FFDHE_3072: case WOLFSSL_FFDHE_4096: case WOLFSSL_FFDHE_6144: case WOLFSSL_FFDHE_8192: #ifdef HAVE_PQC case WOLFSSL_KYBER_LEVEL1: case WOLFSSL_KYBER_LEVEL3: case WOLFSSL_KYBER_LEVEL5: case WOLFSSL_NTRU_HPS_LEVEL1: case WOLFSSL_NTRU_HPS_LEVEL3: case WOLFSSL_NTRU_HPS_LEVEL5: case WOLFSSL_NTRU_HRSS_LEVEL3: case WOLFSSL_SABER_LEVEL1: case WOLFSSL_SABER_LEVEL3: case WOLFSSL_SABER_LEVEL5: case WOLFSSL_KYBER_90S_LEVEL1: case WOLFSSL_KYBER_90S_LEVEL3: case WOLFSSL_KYBER_90S_LEVEL5: case WOLFSSL_P256_NTRU_HPS_LEVEL1: case WOLFSSL_P384_NTRU_HPS_LEVEL3: case WOLFSSL_P521_NTRU_HPS_LEVEL5: case WOLFSSL_P384_NTRU_HRSS_LEVEL3: case WOLFSSL_P256_SABER_LEVEL1: case WOLFSSL_P384_SABER_LEVEL3: case WOLFSSL_P521_SABER_LEVEL5: case WOLFSSL_P256_KYBER_LEVEL1: case WOLFSSL_P384_KYBER_LEVEL3: case WOLFSSL_P521_KYBER_LEVEL5: case WOLFSSL_P256_KYBER_90S_LEVEL1: case WOLFSSL_P384_KYBER_90S_LEVEL3: case WOLFSSL_P521_KYBER_90S_LEVEL5: #endif return 1; default: return 0; } } int wolfSSL_UseSupportedCurve(WOLFSSL* ssl, word16 name) { if (ssl == NULL || !isValidCurveGroup(name)) return BAD_FUNC_ARG; ssl->options.userCurves = 1; return TLSX_UseSupportedCurve(&ssl->extensions, name, ssl->heap); } int wolfSSL_CTX_UseSupportedCurve(WOLFSSL_CTX* ctx, word16 name) { if (ctx == NULL || !isValidCurveGroup(name)) return BAD_FUNC_ARG; ctx->userCurves = 1; return TLSX_UseSupportedCurve(&ctx->extensions, name, ctx->heap); } #if defined(OPENSSL_EXTRA) && defined(WOLFSSL_TLS13) int wolfSSL_CTX_set1_groups(WOLFSSL_CTX* ctx, int* groups, int count) { int i; int _groups[WOLFSSL_MAX_GROUP_COUNT]; WOLFSSL_ENTER("wolfSSL_CTX_set1_groups"); if (count == 0) { WOLFSSL_MSG("Group count is zero"); return WOLFSSL_FAILURE; } for (i = 0; i < count; i++) { if (isValidCurveGroup((word16)groups[i])) { _groups[i] = groups[i]; } #ifdef HAVE_ECC else { /* groups may be populated with curve NIDs */ int oid = nid2oid(groups[i], oidCurveType); int name = (int)GetCurveByOID(oid); if (name == 0) { WOLFSSL_MSG("Invalid group name"); return WOLFSSL_FAILURE; } _groups[i] = name; } #else else { WOLFSSL_MSG("Invalid group name"); return WOLFSSL_FAILURE; } #endif } return wolfSSL_CTX_set_groups(ctx, _groups, count) == WOLFSSL_SUCCESS ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; } int wolfSSL_set1_groups(WOLFSSL* ssl, int* groups, int count) { int i; int _groups[WOLFSSL_MAX_GROUP_COUNT]; WOLFSSL_ENTER("wolfSSL_CTX_set1_groups"); if (count == 0) { WOLFSSL_MSG("Group count is zero"); return WOLFSSL_FAILURE; } for (i = 0; i < count; i++) { if (isValidCurveGroup((word16)groups[i])) { _groups[i] = groups[i]; } #ifdef HAVE_ECC else { /* groups may be populated with curve NIDs */ int oid = nid2oid(groups[i], oidCurveType); int name = (int)GetCurveByOID(oid); if (name == 0) { WOLFSSL_MSG("Invalid group name"); return WOLFSSL_FAILURE; } _groups[i] = name; } #else else { WOLFSSL_MSG("Invalid group name"); return WOLFSSL_FAILURE; } #endif } return wolfSSL_set_groups(ssl, _groups, count) == WOLFSSL_SUCCESS ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; } #endif /* OPENSSL_EXTRA && WOLFSSL_TLS13 */ #endif /* HAVE_SUPPORTED_CURVES */ /* Application-Layer Protocol Negotiation */ #ifdef HAVE_ALPN WOLFSSL_ABI int wolfSSL_UseALPN(WOLFSSL* ssl, char *protocol_name_list, word32 protocol_name_listSz, byte options) { char *list, *ptr, **token; word16 len; int idx = 0; int ret = WOLFSSL_FAILURE; WOLFSSL_ENTER("wolfSSL_UseALPN"); if (ssl == NULL || protocol_name_list == NULL) return BAD_FUNC_ARG; if (protocol_name_listSz > (WOLFSSL_MAX_ALPN_NUMBER * WOLFSSL_MAX_ALPN_PROTO_NAME_LEN + WOLFSSL_MAX_ALPN_NUMBER)) { WOLFSSL_MSG("Invalid arguments, protocol name list too long"); return BAD_FUNC_ARG; } if (!(options & WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) && !(options & WOLFSSL_ALPN_FAILED_ON_MISMATCH)) { WOLFSSL_MSG("Invalid arguments, options not supported"); return BAD_FUNC_ARG; } list = (char *)XMALLOC(protocol_name_listSz+1, ssl->heap, DYNAMIC_TYPE_ALPN); if (list == NULL) { WOLFSSL_MSG("Memory failure"); return MEMORY_ERROR; } token = (char **)XMALLOC(sizeof(char *) * (WOLFSSL_MAX_ALPN_NUMBER+1), ssl->heap, DYNAMIC_TYPE_ALPN); if (token == NULL) { XFREE(list, ssl->heap, DYNAMIC_TYPE_ALPN); WOLFSSL_MSG("Memory failure"); return MEMORY_ERROR; } XMEMSET(token, 0, sizeof(char *) * (WOLFSSL_MAX_ALPN_NUMBER+1)); XSTRNCPY(list, protocol_name_list, protocol_name_listSz); list[protocol_name_listSz] = '\0'; /* read all protocol name from the list */ token[idx] = XSTRTOK(list, ",", &ptr); while (idx < WOLFSSL_MAX_ALPN_NUMBER && token[idx] != NULL) token[++idx] = XSTRTOK(NULL, ",", &ptr); /* add protocol name list in the TLS extension in reverse order */ while ((idx--) > 0) { len = (word16)XSTRLEN(token[idx]); ret = TLSX_UseALPN(&ssl->extensions, token[idx], len, options, ssl->heap); if (ret != WOLFSSL_SUCCESS) { WOLFSSL_MSG("TLSX_UseALPN failure"); break; } } XFREE(token, ssl->heap, DYNAMIC_TYPE_ALPN); XFREE(list, ssl->heap, DYNAMIC_TYPE_ALPN); return ret; } int wolfSSL_ALPN_GetProtocol(WOLFSSL* ssl, char **protocol_name, word16 *size) { return TLSX_ALPN_GetRequest(ssl ? ssl->extensions : NULL, (void **)protocol_name, size); } int wolfSSL_ALPN_GetPeerProtocol(WOLFSSL* ssl, char **list, word16 *listSz) { if (list == NULL || listSz == NULL) return BAD_FUNC_ARG; if (ssl->alpn_client_list == NULL) return BUFFER_ERROR; *listSz = (word16)XSTRLEN(ssl->alpn_client_list); if (*listSz == 0) return BUFFER_ERROR; *list = (char *)XMALLOC((*listSz)+1, ssl->heap, DYNAMIC_TYPE_TLSX); if (*list == NULL) return MEMORY_ERROR; XSTRNCPY(*list, ssl->alpn_client_list, (*listSz)+1); (*list)[*listSz] = 0; return WOLFSSL_SUCCESS; } /* used to free memory allocated by wolfSSL_ALPN_GetPeerProtocol */ int wolfSSL_ALPN_FreePeerProtocol(WOLFSSL* ssl, char **list) { if (ssl == NULL) { return BAD_FUNC_ARG; } XFREE(*list, ssl->heap, DYNAMIC_TYPE_TLSX); *list = NULL; return WOLFSSL_SUCCESS; } #endif /* HAVE_ALPN */ /* Secure Renegotiation */ #ifdef HAVE_SERVER_RENEGOTIATION_INFO /* user is forcing ability to use secure renegotiation, we discourage it */ int wolfSSL_UseSecureRenegotiation(WOLFSSL* ssl) { int ret = BAD_FUNC_ARG; if (ssl) ret = TLSX_UseSecureRenegotiation(&ssl->extensions, ssl->heap); if (ret == WOLFSSL_SUCCESS) { TLSX* extension = TLSX_Find(ssl->extensions, TLSX_RENEGOTIATION_INFO); if (extension) ssl->secure_renegotiation = (SecureRenegotiation*)extension->data; } return ret; } int wolfSSL_CTX_UseSecureRenegotiation(WOLFSSL_CTX* ctx) { if (ctx == NULL) return BAD_FUNC_ARG; ctx->useSecureReneg = 1; return WOLFSSL_SUCCESS; } /* do a secure renegotiation handshake, user forced, we discourage */ static int _Rehandshake(WOLFSSL* ssl) { int ret; if (ssl == NULL) return BAD_FUNC_ARG; if (ssl->secure_renegotiation == NULL) { WOLFSSL_MSG("Secure Renegotiation not forced on by user"); return SECURE_RENEGOTIATION_E; } if (ssl->secure_renegotiation->enabled == 0) { WOLFSSL_MSG("Secure Renegotiation not enabled at extension level"); return SECURE_RENEGOTIATION_E; } /* If the client started the renegotiation, the server will already * have processed the client's hello. */ if (ssl->options.side != WOLFSSL_SERVER_END || ssl->options.acceptState != ACCEPT_FIRST_REPLY_DONE) { if (ssl->options.handShakeState != HANDSHAKE_DONE) { if (!ssl->options.handShakeDone) { WOLFSSL_MSG("Can't renegotiate until initial " "handshake complete"); return SECURE_RENEGOTIATION_E; } else { WOLFSSL_MSG("Renegotiation already started. " "Moving it forward."); ret = wolfSSL_negotiate(ssl); if (ret == WOLFSSL_SUCCESS) ssl->secure_rene_count++; return ret; } } #ifndef NO_FORCE_SCR_SAME_SUITE /* force same suite */ if (ssl->suites) { ssl->suites->suiteSz = SUITE_LEN; ssl->suites->suites[0] = ssl->options.cipherSuite0; ssl->suites->suites[1] = ssl->options.cipherSuite; } #endif /* reset handshake states */ ssl->options.sendVerify = 0; ssl->options.serverState = NULL_STATE; ssl->options.clientState = NULL_STATE; ssl->options.connectState = CONNECT_BEGIN; ssl->options.acceptState = ACCEPT_BEGIN_RENEG; ssl->options.handShakeState = NULL_STATE; ssl->options.processReply = 0; /* TODO, move states in internal.h */ XMEMSET(&ssl->msgsReceived, 0, sizeof(ssl->msgsReceived)); ssl->secure_renegotiation->cache_status = SCR_CACHE_NEEDED; #if !defined(NO_WOLFSSL_SERVER) && defined(HAVE_SECURE_RENEGOTIATION) if (ssl->options.side == WOLFSSL_SERVER_END) { ret = SendHelloRequest(ssl); if (ret != 0) { ssl->error = ret; return WOLFSSL_FATAL_ERROR; } } #endif /* !NO_WOLFSSL_SERVER && HAVE_SECURE_RENEGOTIATION */ ret = InitHandshakeHashes(ssl); if (ret != 0) { ssl->error = ret; return WOLFSSL_FATAL_ERROR; } } ret = wolfSSL_negotiate(ssl); if (ret == WOLFSSL_SUCCESS) ssl->secure_rene_count++; return ret; } /* do a secure renegotiation handshake, user forced, we discourage */ int wolfSSL_Rehandshake(WOLFSSL* ssl) { int ret; WOLFSSL_ENTER("wolfSSL_Rehandshake"); if (ssl == NULL) return WOLFSSL_FAILURE; #ifdef HAVE_SESSION_TICKET ret = WOLFSSL_SUCCESS; #endif if (ssl->options.side == WOLFSSL_SERVER_END) { /* Reset option to send certificate verify. */ ssl->options.sendVerify = 0; } else { /* Reset resuming flag to do full secure handshake. */ ssl->options.resuming = 0; #ifdef HAVE_SESSION_TICKET /* Clearing the ticket. */ ret = wolfSSL_UseSessionTicket(ssl); #endif } /* CLIENT/SERVER: Reset peer authentication for full secure handshake. */ ssl->options.peerAuthGood = 0; #ifdef HAVE_SESSION_TICKET if (ret == WOLFSSL_SUCCESS) #endif ret = _Rehandshake(ssl); return ret; } #ifndef NO_WOLFSSL_CLIENT /* do a secure resumption handshake, user forced, we discourage */ int wolfSSL_SecureResume(WOLFSSL* ssl) { WOLFSSL_ENTER("wolfSSL_SecureResume"); if (ssl == NULL) return BAD_FUNC_ARG; if (ssl->options.side == WOLFSSL_SERVER_END) { ssl->error = SIDE_ERROR; return WOLFSSL_FATAL_ERROR; } return _Rehandshake(ssl); } #endif /* NO_WOLFSSL_CLIENT */ long wolfSSL_SSL_get_secure_renegotiation_support(WOLFSSL* ssl) { WOLFSSL_ENTER("wolfSSL_SSL_get_secure_renegotiation_support"); if (!ssl || !ssl->secure_renegotiation) return WOLFSSL_FAILURE; return ssl->secure_renegotiation->enabled; } #endif /* HAVE_SECURE_RENEGOTIATION_INFO */ #if defined(HAVE_SESSION_TICKET) /* Session Ticket */ #if !defined(NO_WOLFSSL_SERVER) int wolfSSL_CTX_NoTicketTLSv12(WOLFSSL_CTX* ctx) { if (ctx == NULL) return BAD_FUNC_ARG; ctx->noTicketTls12 = 1; return WOLFSSL_SUCCESS; } int wolfSSL_NoTicketTLSv12(WOLFSSL* ssl) { if (ssl == NULL) return BAD_FUNC_ARG; ssl->options.noTicketTls12 = 1; return WOLFSSL_SUCCESS; } /* WOLFSSL_SUCCESS on ok */ int wolfSSL_CTX_set_TicketEncCb(WOLFSSL_CTX* ctx, SessionTicketEncCb cb) { if (ctx == NULL) return BAD_FUNC_ARG; ctx->ticketEncCb = cb; return WOLFSSL_SUCCESS; } /* set hint interval, WOLFSSL_SUCCESS on ok */ int wolfSSL_CTX_set_TicketHint(WOLFSSL_CTX* ctx, int hint) { if (ctx == NULL) return BAD_FUNC_ARG; ctx->ticketHint = hint; return WOLFSSL_SUCCESS; } /* set user context, WOLFSSL_SUCCESS on ok */ int wolfSSL_CTX_set_TicketEncCtx(WOLFSSL_CTX* ctx, void* userCtx) { if (ctx == NULL) return BAD_FUNC_ARG; ctx->ticketEncCtx = userCtx; return WOLFSSL_SUCCESS; } /* get user context - returns userCtx on success, NULL on failure */ void* wolfSSL_CTX_get_TicketEncCtx(WOLFSSL_CTX* ctx) { if (ctx == NULL) return NULL; return ctx->ticketEncCtx; } #ifdef WOLFSSL_TLS13 /* set the maximum number of tickets to send * return WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE on fail */ int wolfSSL_CTX_set_num_tickets(WOLFSSL_CTX* ctx, size_t mxTickets) { if (ctx == NULL) return WOLFSSL_FAILURE; ctx->maxTicketTls13 = (unsigned int)mxTickets; return WOLFSSL_SUCCESS; } /* get the maximum number of tickets to send * return number of tickets set to be sent */ size_t wolfSSL_CTX_get_num_tickets(WOLFSSL_CTX* ctx) { if (ctx == NULL) return 0; return (size_t)ctx->maxTicketTls13; } #endif /* WOLFSSL_TLS13 */ #endif /* !NO_WOLFSSL_SERVER */ #if !defined(NO_WOLFSSL_CLIENT) int wolfSSL_UseSessionTicket(WOLFSSL* ssl) { if (ssl == NULL) return BAD_FUNC_ARG; return TLSX_UseSessionTicket(&ssl->extensions, NULL, ssl->heap); } int wolfSSL_CTX_UseSessionTicket(WOLFSSL_CTX* ctx) { if (ctx == NULL) return BAD_FUNC_ARG; return TLSX_UseSessionTicket(&ctx->extensions, NULL, ctx->heap); } WOLFSSL_API int wolfSSL_get_SessionTicket(WOLFSSL* ssl, byte* buf, word32* bufSz) { if (ssl == NULL || buf == NULL || bufSz == NULL || *bufSz == 0) return BAD_FUNC_ARG; if (ssl->session->ticketLen <= *bufSz) { XMEMCPY(buf, ssl->session->ticket, ssl->session->ticketLen); *bufSz = ssl->session->ticketLen; } else *bufSz = 0; return WOLFSSL_SUCCESS; } WOLFSSL_API int wolfSSL_set_SessionTicket(WOLFSSL* ssl, const byte* buf, word32 bufSz) { if (ssl == NULL || (buf == NULL && bufSz > 0)) return BAD_FUNC_ARG; if (bufSz > 0) { /* Ticket will fit into static ticket */ if (bufSz <= SESSION_TICKET_LEN) { if (ssl->session->ticketLenAlloc > 0) { XFREE(ssl->session->ticket, ssl->session->heap, DYNAMIC_TYPE_SESSION_TICK); ssl->session->ticketLenAlloc = 0; ssl->session->ticket = ssl->session->_staticTicket; } } else { /* Ticket requires dynamic ticket storage */ if (ssl->session->ticketLen < bufSz) { /* is dyn buffer big enough */ if (ssl->session->ticketLenAlloc > 0) { XFREE(ssl->session->ticket, ssl->session->heap, DYNAMIC_TYPE_SESSION_TICK); } ssl->session->ticket = (byte*)XMALLOC(bufSz, ssl->session->heap, DYNAMIC_TYPE_SESSION_TICK); if(ssl->session->ticket == NULL) { ssl->session->ticket = ssl->session->_staticTicket; ssl->session->ticketLenAlloc = 0; return MEMORY_ERROR; } ssl->session->ticketLenAlloc = (word16)bufSz; } } XMEMCPY(ssl->session->ticket, buf, bufSz); } ssl->session->ticketLen = (word16)bufSz; return WOLFSSL_SUCCESS; } WOLFSSL_API int wolfSSL_set_SessionTicket_cb(WOLFSSL* ssl, CallbackSessionTicket cb, void* ctx) { if (ssl == NULL) return BAD_FUNC_ARG; ssl->session_ticket_cb = cb; ssl->session_ticket_ctx = ctx; return WOLFSSL_SUCCESS; } #endif /* !NO_WOLFSSL_CLIENT */ #endif /* HAVE_SESSION_TICKET */ #ifdef HAVE_EXTENDED_MASTER #ifndef NO_WOLFSSL_CLIENT int wolfSSL_CTX_DisableExtendedMasterSecret(WOLFSSL_CTX* ctx) { if (ctx == NULL) return BAD_FUNC_ARG; ctx->haveEMS = 0; return WOLFSSL_SUCCESS; } int wolfSSL_DisableExtendedMasterSecret(WOLFSSL* ssl) { if (ssl == NULL) return BAD_FUNC_ARG; ssl->options.haveEMS = 0; return WOLFSSL_SUCCESS; } #endif #endif #ifndef WOLFSSL_LEANPSK int wolfSSL_send(WOLFSSL* ssl, const void* data, int sz, int flags) { int ret; int oldFlags; WOLFSSL_ENTER("wolfSSL_send()"); if (ssl == NULL || data == NULL || sz < 0) return BAD_FUNC_ARG; oldFlags = ssl->wflags; ssl->wflags = flags; ret = wolfSSL_write(ssl, data, sz); ssl->wflags = oldFlags; WOLFSSL_LEAVE("wolfSSL_send()", ret); return ret; } int wolfSSL_recv(WOLFSSL* ssl, void* data, int sz, int flags) { int ret; int oldFlags; WOLFSSL_ENTER("wolfSSL_recv()"); if (ssl == NULL || data == NULL || sz < 0) return BAD_FUNC_ARG; oldFlags = ssl->rflags; ssl->rflags = flags; ret = wolfSSL_read(ssl, data, sz); ssl->rflags = oldFlags; WOLFSSL_LEAVE("wolfSSL_recv()", ret); return ret; } #endif /* WOLFSSL_SUCCESS on ok */ WOLFSSL_ABI int wolfSSL_shutdown(WOLFSSL* ssl) { int ret = WOLFSSL_FATAL_ERROR; WOLFSSL_ENTER("SSL_shutdown()"); if (ssl == NULL) return WOLFSSL_FATAL_ERROR; if (ssl->options.quietShutdown) { WOLFSSL_MSG("quiet shutdown, no close notify sent"); ret = WOLFSSL_SUCCESS; } else { /* try to send close notify, not an error if can't */ if (!ssl->options.isClosed && !ssl->options.connReset && !ssl->options.sentNotify) { ssl->error = SendAlert(ssl, alert_warning, close_notify); if (ssl->error < 0) { WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } ssl->options.sentNotify = 1; /* don't send close_notify twice */ if (ssl->options.closeNotify) ret = WOLFSSL_SUCCESS; else { ret = WOLFSSL_SHUTDOWN_NOT_DONE; WOLFSSL_LEAVE("SSL_shutdown()", ret); return ret; } } #ifdef WOLFSSL_SHUTDOWNONCE if (ssl->options.isClosed || ssl->options.connReset) { /* Shutdown has already occurred. * Caller is free to ignore this error. */ return SSL_SHUTDOWN_ALREADY_DONE_E; } #endif /* call wolfSSL_shutdown again for bidirectional shutdown */ if (ssl->options.sentNotify && !ssl->options.closeNotify) { ret = ProcessReply(ssl); if (ret == ZERO_RETURN) { /* simulate OpenSSL behavior */ ssl->error = WOLFSSL_ERROR_SYSCALL; ret = WOLFSSL_SUCCESS; } else if (ssl->error == WOLFSSL_ERROR_NONE) { ret = WOLFSSL_SHUTDOWN_NOT_DONE; } else { WOLFSSL_ERROR(ssl->error); ret = WOLFSSL_FATAL_ERROR; } } } #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) /* reset WOLFSSL structure state for possible re-use */ if (ret == WOLFSSL_SUCCESS) { if (wolfSSL_clear(ssl) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("could not clear WOLFSSL"); ret = WOLFSSL_FATAL_ERROR; } } #endif WOLFSSL_LEAVE("SSL_shutdown()", ret); return ret; } /* get current error state value */ int wolfSSL_state(WOLFSSL* ssl) { if (ssl == NULL) { return BAD_FUNC_ARG; } return ssl->error; } WOLFSSL_ABI int wolfSSL_get_error(WOLFSSL* ssl, int ret) { WOLFSSL_ENTER("SSL_get_error"); if (ret > 0) return WOLFSSL_ERROR_NONE; if (ssl == NULL) return BAD_FUNC_ARG; WOLFSSL_LEAVE("SSL_get_error", ssl->error); /* make sure converted types are handled in SetErrorString() too */ if (ssl->error == WANT_READ) return WOLFSSL_ERROR_WANT_READ; /* convert to OpenSSL type */ else if (ssl->error == WANT_WRITE) return WOLFSSL_ERROR_WANT_WRITE; /* convert to OpenSSL type */ else if (ssl->error == ZERO_RETURN) return WOLFSSL_ERROR_ZERO_RETURN; /* convert to OpenSSL type */ return ssl->error; } /* retrieve alert history, WOLFSSL_SUCCESS on ok */ int wolfSSL_get_alert_history(WOLFSSL* ssl, WOLFSSL_ALERT_HISTORY *h) { if (ssl && h) { *h = ssl->alert_history; } return WOLFSSL_SUCCESS; } #ifdef OPENSSL_EXTRA /* returns SSL_WRITING, SSL_READING or SSL_NOTHING */ int wolfSSL_want(WOLFSSL* ssl) { int rw_state = SSL_NOTHING; if (ssl) { if (ssl->error == WANT_READ) rw_state = SSL_READING; else if (ssl->error == WANT_WRITE) rw_state = SSL_WRITING; } return rw_state; } #endif /* return TRUE if current error is want read */ int wolfSSL_want_read(WOLFSSL* ssl) { WOLFSSL_ENTER("SSL_want_read"); if (ssl->error == WANT_READ) return 1; return 0; } /* return TRUE if current error is want write */ int wolfSSL_want_write(WOLFSSL* ssl) { WOLFSSL_ENTER("SSL_want_write"); if (ssl->error == WANT_WRITE) return 1; return 0; } char* wolfSSL_ERR_error_string(unsigned long errNumber, char* data) { static char tmp[WOLFSSL_MAX_ERROR_SZ] = {0}; WOLFSSL_ENTER("ERR_error_string"); if (data) { SetErrorString((int)errNumber, data); return data; } else { SetErrorString((int)errNumber, tmp); return tmp; } } void wolfSSL_ERR_error_string_n(unsigned long e, char* buf, unsigned long len) { WOLFSSL_ENTER("wolfSSL_ERR_error_string_n"); if (len >= WOLFSSL_MAX_ERROR_SZ) wolfSSL_ERR_error_string(e, buf); else { char tmp[WOLFSSL_MAX_ERROR_SZ]; WOLFSSL_MSG("Error buffer too short, truncating"); if (len) { wolfSSL_ERR_error_string(e, tmp); XMEMCPY(buf, tmp, len-1); buf[len-1] = '\0'; } } } /* don't free temporary arrays at end of handshake */ void wolfSSL_KeepArrays(WOLFSSL* ssl) { if (ssl) ssl->options.saveArrays = 1; } /* user doesn't need temporary arrays anymore, Free */ void wolfSSL_FreeArrays(WOLFSSL* ssl) { if (ssl && ssl->options.handShakeState == HANDSHAKE_DONE) { ssl->options.saveArrays = 0; FreeArrays(ssl, 1); } } /* Set option to indicate that the resources are not to be freed after * handshake. * * ssl The SSL/TLS object. * returns BAD_FUNC_ARG when ssl is NULL and 0 on success. */ int wolfSSL_KeepHandshakeResources(WOLFSSL* ssl) { if (ssl == NULL) return BAD_FUNC_ARG; ssl->options.keepResources = 1; return 0; } /* Free the handshake resources after handshake. * * ssl The SSL/TLS object. * returns BAD_FUNC_ARG when ssl is NULL and 0 on success. */ int wolfSSL_FreeHandshakeResources(WOLFSSL* ssl) { if (ssl == NULL) return BAD_FUNC_ARG; FreeHandshakeResources(ssl); return 0; } /* Use the client's order of preference when matching cipher suites. * * ssl The SSL/TLS context object. * returns BAD_FUNC_ARG when ssl is NULL and 0 on success. */ int wolfSSL_CTX_UseClientSuites(WOLFSSL_CTX* ctx) { if (ctx == NULL) return BAD_FUNC_ARG; ctx->useClientOrder = 1; return 0; } /* Use the client's order of preference when matching cipher suites. * * ssl The SSL/TLS object. * returns BAD_FUNC_ARG when ssl is NULL and 0 on success. */ int wolfSSL_UseClientSuites(WOLFSSL* ssl) { if (ssl == NULL) return BAD_FUNC_ARG; ssl->options.useClientOrder = 1; return 0; } #ifdef WOLFSSL_DTLS const byte* wolfSSL_GetDtlsMacSecret(WOLFSSL* ssl, int verify, int epochOrder) { #ifndef WOLFSSL_AEAD_ONLY Keys* keys = NULL; (void)epochOrder; if (ssl == NULL) return NULL; #ifdef HAVE_SECURE_RENEGOTIATION switch (epochOrder) { case PEER_ORDER: if (IsDtlsMsgSCRKeys(ssl)) keys = &ssl->secure_renegotiation->tmp_keys; else keys = &ssl->keys; break; case PREV_ORDER: keys = &ssl->keys; break; case CUR_ORDER: if (DtlsUseSCRKeys(ssl)) keys = &ssl->secure_renegotiation->tmp_keys; else keys = &ssl->keys; break; default: WOLFSSL_MSG("Unknown epoch order"); return NULL; } #else keys = &ssl->keys; #endif if ( (ssl->options.side == WOLFSSL_CLIENT_END && !verify) || (ssl->options.side == WOLFSSL_SERVER_END && verify) ) return keys->client_write_MAC_secret; else return keys->server_write_MAC_secret; #else (void)ssl; (void)verify; (void)epochOrder; return NULL; #endif } #endif /* WOLFSSL_DTLS */ const byte* wolfSSL_GetMacSecret(WOLFSSL* ssl, int verify) { #ifndef WOLFSSL_AEAD_ONLY if (ssl == NULL) return NULL; if ( (ssl->options.side == WOLFSSL_CLIENT_END && !verify) || (ssl->options.side == WOLFSSL_SERVER_END && verify) ) return ssl->keys.client_write_MAC_secret; else return ssl->keys.server_write_MAC_secret; #else (void)ssl; (void)verify; return NULL; #endif } #ifdef ATOMIC_USER void wolfSSL_CTX_SetMacEncryptCb(WOLFSSL_CTX* ctx, CallbackMacEncrypt cb) { if (ctx) ctx->MacEncryptCb = cb; } void wolfSSL_SetMacEncryptCtx(WOLFSSL* ssl, void *ctx) { if (ssl) ssl->MacEncryptCtx = ctx; } void* wolfSSL_GetMacEncryptCtx(WOLFSSL* ssl) { if (ssl) return ssl->MacEncryptCtx; return NULL; } void wolfSSL_CTX_SetDecryptVerifyCb(WOLFSSL_CTX* ctx, CallbackDecryptVerify cb) { if (ctx) ctx->DecryptVerifyCb = cb; } void wolfSSL_SetDecryptVerifyCtx(WOLFSSL* ssl, void *ctx) { if (ssl) ssl->DecryptVerifyCtx = ctx; } void* wolfSSL_GetDecryptVerifyCtx(WOLFSSL* ssl) { if (ssl) return ssl->DecryptVerifyCtx; return NULL; } #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) /** * Set the callback, against the context, that encrypts then MACs. * * ctx SSL/TLS context. * cb Callback function to use with Encrypt-Then-MAC. */ void wolfSSL_CTX_SetEncryptMacCb(WOLFSSL_CTX* ctx, CallbackEncryptMac cb) { if (ctx) ctx->EncryptMacCb = cb; } /** * Set the context to use with callback that encrypts then MACs. * * ssl SSL/TLS object. * ctx Callback function's context. */ void wolfSSL_SetEncryptMacCtx(WOLFSSL* ssl, void *ctx) { if (ssl) ssl->EncryptMacCtx = ctx; } /** * Get the context being used with callback that encrypts then MACs. * * ssl SSL/TLS object. * returns callback function's context or NULL if SSL/TLS object is NULL. */ void* wolfSSL_GetEncryptMacCtx(WOLFSSL* ssl) { if (ssl) return ssl->EncryptMacCtx; return NULL; } /** * Set the callback, against the context, that MAC verifies then decrypts. * * ctx SSL/TLS context. * cb Callback function to use with Encrypt-Then-MAC. */ void wolfSSL_CTX_SetVerifyDecryptCb(WOLFSSL_CTX* ctx, CallbackVerifyDecrypt cb) { if (ctx) ctx->VerifyDecryptCb = cb; } /** * Set the context to use with callback that MAC verifies then decrypts. * * ssl SSL/TLS object. * ctx Callback function's context. */ void wolfSSL_SetVerifyDecryptCtx(WOLFSSL* ssl, void *ctx) { if (ssl) ssl->VerifyDecryptCtx = ctx; } /** * Get the context being used with callback that MAC verifies then decrypts. * * ssl SSL/TLS object. * returns callback function's context or NULL if SSL/TLS object is NULL. */ void* wolfSSL_GetVerifyDecryptCtx(WOLFSSL* ssl) { if (ssl) return ssl->VerifyDecryptCtx; return NULL; } #endif /* HAVE_ENCRYPT_THEN_MAC !WOLFSSL_AEAD_ONLY */ const byte* wolfSSL_GetClientWriteKey(WOLFSSL* ssl) { if (ssl) return ssl->keys.client_write_key; return NULL; } const byte* wolfSSL_GetClientWriteIV(WOLFSSL* ssl) { if (ssl) return ssl->keys.client_write_IV; return NULL; } const byte* wolfSSL_GetServerWriteKey(WOLFSSL* ssl) { if (ssl) return ssl->keys.server_write_key; return NULL; } const byte* wolfSSL_GetServerWriteIV(WOLFSSL* ssl) { if (ssl) return ssl->keys.server_write_IV; return NULL; } int wolfSSL_GetKeySize(WOLFSSL* ssl) { if (ssl) return ssl->specs.key_size; return BAD_FUNC_ARG; } int wolfSSL_GetIVSize(WOLFSSL* ssl) { if (ssl) return ssl->specs.iv_size; return BAD_FUNC_ARG; } int wolfSSL_GetBulkCipher(WOLFSSL* ssl) { if (ssl) return ssl->specs.bulk_cipher_algorithm; return BAD_FUNC_ARG; } int wolfSSL_GetCipherType(WOLFSSL* ssl) { if (ssl == NULL) return BAD_FUNC_ARG; #ifndef WOLFSSL_AEAD_ONLY if (ssl->specs.cipher_type == block) return WOLFSSL_BLOCK_TYPE; if (ssl->specs.cipher_type == stream) return WOLFSSL_STREAM_TYPE; #endif if (ssl->specs.cipher_type == aead) return WOLFSSL_AEAD_TYPE; return -1; } int wolfSSL_GetCipherBlockSize(WOLFSSL* ssl) { if (ssl == NULL) return BAD_FUNC_ARG; return ssl->specs.block_size; } int wolfSSL_GetAeadMacSize(WOLFSSL* ssl) { if (ssl == NULL) return BAD_FUNC_ARG; return ssl->specs.aead_mac_size; } int wolfSSL_IsTLSv1_1(WOLFSSL* ssl) { if (ssl == NULL) return BAD_FUNC_ARG; if (ssl->options.tls1_1) return 1; return 0; } int wolfSSL_GetSide(WOLFSSL* ssl) { if (ssl) return ssl->options.side; return BAD_FUNC_ARG; } int wolfSSL_GetHmacSize(WOLFSSL* ssl) { /* AEAD ciphers don't have HMAC keys */ if (ssl) return (ssl->specs.cipher_type != aead) ? ssl->specs.hash_size : 0; return BAD_FUNC_ARG; } #ifdef WORD64_AVAILABLE int wolfSSL_GetPeerSequenceNumber(WOLFSSL* ssl, word64 *seq) { if ((ssl == NULL) || (seq == NULL)) return BAD_FUNC_ARG; *seq = ((word64)ssl->keys.peer_sequence_number_hi << 32) | ssl->keys.peer_sequence_number_lo; return !(*seq); } int wolfSSL_GetSequenceNumber(WOLFSSL* ssl, word64 *seq) { if ((ssl == NULL) || (seq == NULL)) return BAD_FUNC_ARG; *seq = ((word64)ssl->keys.sequence_number_hi << 32) | ssl->keys.sequence_number_lo; return !(*seq); } #endif #endif /* ATOMIC_USER */ #ifndef NO_CERTS WOLFSSL_CERT_MANAGER* wolfSSL_CTX_GetCertManager(WOLFSSL_CTX* ctx) { WOLFSSL_CERT_MANAGER* cm = NULL; if (ctx) cm = ctx->cm; return cm; } WOLFSSL_CERT_MANAGER* wolfSSL_CertManagerNew_ex(void* heap) { WOLFSSL_CERT_MANAGER* cm; WOLFSSL_ENTER("wolfSSL_CertManagerNew"); cm = (WOLFSSL_CERT_MANAGER*) XMALLOC(sizeof(WOLFSSL_CERT_MANAGER), heap, DYNAMIC_TYPE_CERT_MANAGER); if (cm) { XMEMSET(cm, 0, sizeof(WOLFSSL_CERT_MANAGER)); cm->refCount = 1; if (wc_InitMutex(&cm->caLock) != 0) { WOLFSSL_MSG("Bad mutex init"); wolfSSL_CertManagerFree(cm); return NULL; } #ifndef SINGLE_THREADED if (wc_InitMutex(&cm->refMutex) != 0) { WOLFSSL_MSG("Bad mutex init"); wolfSSL_CertManagerFree(cm); return NULL; } #endif #ifdef WOLFSSL_TRUST_PEER_CERT if (wc_InitMutex(&cm->tpLock) != 0) { WOLFSSL_MSG("Bad mutex init"); wolfSSL_CertManagerFree(cm); return NULL; } #endif /* set default minimum key size allowed */ #ifndef NO_RSA cm->minRsaKeySz = MIN_RSAKEY_SZ; #endif #ifdef HAVE_ECC cm->minEccKeySz = MIN_ECCKEY_SZ; #endif #ifdef HAVE_PQC cm->minFalconKeySz = MIN_FALCONKEY_SZ; #endif cm->heap = heap; } return cm; } WOLFSSL_CERT_MANAGER* wolfSSL_CertManagerNew(void) { return wolfSSL_CertManagerNew_ex(NULL); } void wolfSSL_CertManagerFree(WOLFSSL_CERT_MANAGER* cm) { int doFree = 0; WOLFSSL_ENTER("wolfSSL_CertManagerFree"); if (cm) { #ifndef SINGLE_THREADED if (wc_LockMutex(&cm->refMutex) != 0) { WOLFSSL_MSG("Couldn't lock cm mutex"); } #endif cm->refCount--; if (cm->refCount == 0) doFree = 1; #ifndef SINGLE_THREADED wc_UnLockMutex(&cm->refMutex); #endif if (doFree) { #ifdef HAVE_CRL if (cm->crl) FreeCRL(cm->crl, 1); #endif #ifdef HAVE_OCSP if (cm->ocsp) FreeOCSP(cm->ocsp, 1); XFREE(cm->ocspOverrideURL, cm->heap, DYNAMIC_TYPE_URL); #if !defined(NO_WOLFSSL_SERVER) && \ (defined(HAVE_CERTIFICATE_STATUS_REQUEST) || \ defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)) if (cm->ocsp_stapling) FreeOCSP(cm->ocsp_stapling, 1); #endif #endif FreeSignerTable(cm->caTable, CA_TABLE_SIZE, cm->heap); wc_FreeMutex(&cm->caLock); #ifdef WOLFSSL_TRUST_PEER_CERT FreeTrustedPeerTable(cm->tpTable, TP_TABLE_SIZE, cm->heap); wc_FreeMutex(&cm->tpLock); #endif #ifndef SINGLE_THREADED if (wc_FreeMutex(&cm->refMutex) != 0) { WOLFSSL_MSG("Couldn't free refMutex mutex"); } #endif XFREE(cm, cm->heap, DYNAMIC_TYPE_CERT_MANAGER); } } } int wolfSSL_CertManager_up_ref(WOLFSSL_CERT_MANAGER* cm) { if (cm) { #ifndef SINGLE_THREADED if (wc_LockMutex(&cm->refMutex) != 0) { WOLFSSL_MSG("Failed to lock cm mutex"); return WOLFSSL_FAILURE; } #endif cm->refCount++; #ifndef SINGLE_THREADED wc_UnLockMutex(&cm->refMutex); #endif return WOLFSSL_SUCCESS; } return WOLFSSL_FAILURE; } #if defined(OPENSSL_EXTRA) && !defined(NO_FILESYSTEM) #if defined(WOLFSSL_SIGNER_DER_CERT) /****************************************************************************** * wolfSSL_CertManagerGetCerts - retrieve stack of X509 certificates in a * certificate manager (CM). * * RETURNS: * returns stack of X509 certs on success, otherwise returns a NULL. */ WOLFSSL_STACK* wolfSSL_CertManagerGetCerts(WOLFSSL_CERT_MANAGER* cm) { WOLFSSL_STACK* sk = NULL; int numCerts = 0; DerBuffer** certBuffers = NULL; const byte* derBuffer = NULL; Signer* signers = NULL; word32 row = 0; WOLFSSL_X509* x509 = NULL; int i = 0; int ret = 0; if (cm == NULL) return NULL; sk = wolfSSL_sk_X509_new(); if (sk == NULL) goto error; if (wc_LockMutex(&cm->caLock) != 0) goto error; /* Iterate once to get the number of certs, for memory allocation purposes. */ for (row = 0; row < CA_TABLE_SIZE; row++) { signers = cm->caTable[row]; while (signers && signers->derCert && signers->derCert->buffer) { ++numCerts; signers = signers->next; } } if (numCerts == 0) { wc_UnLockMutex(&cm->caLock); goto error; } certBuffers = (DerBuffer**)XMALLOC(sizeof(DerBuffer*) * numCerts, cm->heap, DYNAMIC_TYPE_TMP_BUFFER); if (certBuffers == NULL) { wc_UnLockMutex(&cm->caLock); goto error; } XMEMSET(certBuffers, 0, sizeof(DerBuffer*) * numCerts); /* Copy the certs locally so that we can release the caLock. If the lock is held when wolfSSL_d2i_X509 is called, GetCA will also try to get the lock, leading to deadlock. */ for (row = 0; row < CA_TABLE_SIZE; row++) { signers = cm->caTable[row]; while (signers && signers->derCert && signers->derCert->buffer) { ret = AllocDer(&certBuffers[i], signers->derCert->length, CA_TYPE, cm->heap); if (ret < 0) { wc_UnLockMutex(&cm->caLock); goto error; } XMEMCPY(certBuffers[i]->buffer, signers->derCert->buffer, signers->derCert->length); certBuffers[i]->length = signers->derCert->length; ++i; signers = signers->next; } } wc_UnLockMutex(&cm->caLock); for (i = 0; i < numCerts; ++i) { derBuffer = certBuffers[i]->buffer; wolfSSL_d2i_X509(&x509, &derBuffer, certBuffers[i]->length); if (x509 == NULL) goto error; if (wolfSSL_sk_X509_push(sk, x509) != WOLFSSL_SUCCESS) goto error; } for (i = 0; i < numCerts && certBuffers[i] != NULL; ++i) { FreeDer(&certBuffers[i]); } XFREE(certBuffers, cm->heap, DYNAMIC_TYPE_TMP_BUFFER); return sk; error: if (sk) wolfSSL_sk_X509_pop_free(sk, NULL); if (certBuffers != NULL) { for (i = 0; i < numCerts && certBuffers[i] != NULL; ++i) { FreeDer(&certBuffers[i]); } } if (certBuffers) XFREE(certBuffers, cm->heap, DYNAMIC_TYPE_TMP_BUFFER); return NULL; } #endif /* WOLFSSL_SIGNER_DER_CERT */ #endif /* OPENSSL_EXTRA && !NO_FILESYSTEM */ /* Unload the CA signer list */ int wolfSSL_CertManagerUnloadCAs(WOLFSSL_CERT_MANAGER* cm) { WOLFSSL_ENTER("wolfSSL_CertManagerUnloadCAs"); if (cm == NULL) return BAD_FUNC_ARG; if (wc_LockMutex(&cm->caLock) != 0) return BAD_MUTEX_E; FreeSignerTable(cm->caTable, CA_TABLE_SIZE, cm->heap); wc_UnLockMutex(&cm->caLock); return WOLFSSL_SUCCESS; } #ifdef WOLFSSL_TRUST_PEER_CERT int wolfSSL_CertManagerUnload_trust_peers(WOLFSSL_CERT_MANAGER* cm) { WOLFSSL_ENTER("wolfSSL_CertManagerUnload_trust_peers"); if (cm == NULL) return BAD_FUNC_ARG; if (wc_LockMutex(&cm->tpLock) != 0) return BAD_MUTEX_E; FreeTrustedPeerTable(cm->tpTable, TP_TABLE_SIZE, cm->heap); wc_UnLockMutex(&cm->tpLock); return WOLFSSL_SUCCESS; } #endif /* WOLFSSL_TRUST_PEER_CERT */ #endif /* NO_CERTS */ #if !defined(NO_FILESYSTEM) && !defined(NO_STDIO_FILESYSTEM) void wolfSSL_ERR_print_errors_fp(XFILE fp, int err) { char data[WOLFSSL_MAX_ERROR_SZ + 1]; WOLFSSL_ENTER("wolfSSL_ERR_print_errors_fp"); SetErrorString(err, data); XFPRINTF(fp, "%s", data); } #if defined(OPENSSL_EXTRA) || defined(DEBUG_WOLFSSL_VERBOSE) void wolfSSL_ERR_dump_errors_fp(XFILE fp) { wc_ERR_print_errors_fp(fp); } void wolfSSL_ERR_print_errors_cb (int (*cb)(const char *str, size_t len, void *u), void *u) { wc_ERR_print_errors_cb(cb, u); } #endif #endif /* * TODO This ssl parameter needs to be changed to const once our ABI checker * stops flagging qualifier additions as ABI breaking. */ WOLFSSL_ABI int wolfSSL_pending(WOLFSSL* ssl) { WOLFSSL_ENTER("SSL_pending"); if (ssl == NULL) return WOLFSSL_FAILURE; return ssl->buffers.clearOutputBuffer.length; } int wolfSSL_has_pending(const WOLFSSL* ssl) { WOLFSSL_ENTER("wolfSSL_has_pending"); if (ssl == NULL) return WOLFSSL_FAILURE; return ssl->buffers.clearOutputBuffer.length > 0; } #ifndef WOLFSSL_LEANPSK /* turn on handshake group messages for context */ int wolfSSL_CTX_set_group_messages(WOLFSSL_CTX* ctx) { if (ctx == NULL) return BAD_FUNC_ARG; ctx->groupMessages = 1; return WOLFSSL_SUCCESS; } #endif #ifndef NO_WOLFSSL_CLIENT /* connect enough to get peer cert chain */ int wolfSSL_connect_cert(WOLFSSL* ssl) { int ret; if (ssl == NULL) return WOLFSSL_FAILURE; ssl->options.certOnly = 1; ret = wolfSSL_connect(ssl); ssl->options.certOnly = 0; return ret; } #endif #ifndef WOLFSSL_LEANPSK /* turn on handshake group messages for ssl object */ int wolfSSL_set_group_messages(WOLFSSL* ssl) { if (ssl == NULL) return BAD_FUNC_ARG; ssl->options.groupMessages = 1; return WOLFSSL_SUCCESS; } /* make minVersion the internal equivalent SSL version */ static int SetMinVersionHelper(byte* minVersion, int version) { #ifdef NO_TLS (void)minVersion; #endif switch (version) { #if defined(WOLFSSL_ALLOW_SSLV3) && !defined(NO_OLD_TLS) case WOLFSSL_SSLV3: *minVersion = SSLv3_MINOR; break; #endif #ifndef NO_TLS #ifndef NO_OLD_TLS #ifdef WOLFSSL_ALLOW_TLSV10 case WOLFSSL_TLSV1: *minVersion = TLSv1_MINOR; break; #endif case WOLFSSL_TLSV1_1: *minVersion = TLSv1_1_MINOR; break; #endif #ifndef WOLFSSL_NO_TLS12 case WOLFSSL_TLSV1_2: *minVersion = TLSv1_2_MINOR; break; #endif #endif #ifdef WOLFSSL_TLS13 case WOLFSSL_TLSV1_3: *minVersion = TLSv1_3_MINOR; break; #endif #ifdef WOLFSSL_DTLS case WOLFSSL_DTLSV1: *minVersion = DTLS_MINOR; break; case WOLFSSL_DTLSV1_2: *minVersion = DTLSv1_2_MINOR; break; #ifdef WOLFSSL_DTLS13 case WOLFSSL_DTLSV1_3: *minVersion = DTLSv1_3_MINOR; break; #endif /* WOLFSSL_DTLS13 */ #endif /* WOLFSSL_DTLS */ default: WOLFSSL_MSG("Bad function argument"); return BAD_FUNC_ARG; } return WOLFSSL_SUCCESS; } /* Set minimum downgrade version allowed, WOLFSSL_SUCCESS on ok */ WOLFSSL_ABI int wolfSSL_CTX_SetMinVersion(WOLFSSL_CTX* ctx, int version) { WOLFSSL_ENTER("wolfSSL_CTX_SetMinVersion"); if (ctx == NULL) { WOLFSSL_MSG("Bad function argument"); return BAD_FUNC_ARG; } return SetMinVersionHelper(&ctx->minDowngrade, version); } /* Set minimum downgrade version allowed, WOLFSSL_SUCCESS on ok */ int wolfSSL_SetMinVersion(WOLFSSL* ssl, int version) { WOLFSSL_ENTER("wolfSSL_SetMinVersion"); if (ssl == NULL) { WOLFSSL_MSG("Bad function argument"); return BAD_FUNC_ARG; } return SetMinVersionHelper(&ssl->options.minDowngrade, version); } /* Function to get version as WOLFSSL_ enum value for wolfSSL_SetVersion */ int wolfSSL_GetVersion(const WOLFSSL* ssl) { if (ssl == NULL) return BAD_FUNC_ARG; if (ssl->version.major == SSLv3_MAJOR) { switch (ssl->version.minor) { case SSLv3_MINOR : return WOLFSSL_SSLV3; case TLSv1_MINOR : return WOLFSSL_TLSV1; case TLSv1_1_MINOR : return WOLFSSL_TLSV1_1; case TLSv1_2_MINOR : return WOLFSSL_TLSV1_2; case TLSv1_3_MINOR : return WOLFSSL_TLSV1_3; default: break; } } return VERSION_ERROR; } int wolfSSL_SetVersion(WOLFSSL* ssl, int version) { word16 haveRSA = 1; word16 havePSK = 0; int keySz = 0; WOLFSSL_ENTER("wolfSSL_SetVersion"); if (ssl == NULL) { WOLFSSL_MSG("Bad function argument"); return BAD_FUNC_ARG; } switch (version) { #if defined(WOLFSSL_ALLOW_SSLV3) && !defined(NO_OLD_TLS) case WOLFSSL_SSLV3: ssl->version = MakeSSLv3(); break; #endif #ifndef NO_TLS #ifndef NO_OLD_TLS #ifdef WOLFSSL_ALLOW_TLSV10 case WOLFSSL_TLSV1: ssl->version = MakeTLSv1(); break; #endif case WOLFSSL_TLSV1_1: ssl->version = MakeTLSv1_1(); break; #endif #ifndef WOLFSSL_NO_TLS12 case WOLFSSL_TLSV1_2: ssl->version = MakeTLSv1_2(); break; #endif #endif #ifdef WOLFSSL_TLS13 case WOLFSSL_TLSV1_3: ssl->version = MakeTLSv1_3(); break; #endif default: WOLFSSL_MSG("Bad function argument"); return BAD_FUNC_ARG; } #ifdef NO_RSA haveRSA = 0; #endif #ifndef NO_PSK havePSK = ssl->options.havePSK; #endif #ifndef NO_CERTS keySz = ssl->buffers.keySz; #endif InitSuites(ssl->suites, ssl->version, keySz, haveRSA, havePSK, ssl->options.haveDH, ssl->options.haveECDSAsig, ssl->options.haveECC, ssl->options.haveStaticECC, ssl->options.haveFalconSig, ssl->options.haveAnon, ssl->options.side); return WOLFSSL_SUCCESS; } #endif /* !leanpsk */ #if !defined(NO_CERTS) || !defined(NO_SESSION_CACHE) /* Make a work from the front of random hash */ static WC_INLINE word32 MakeWordFromHash(const byte* hashID) { return ((word32)hashID[0] << 24) | ((word32)hashID[1] << 16) | ((word32)hashID[2] << 8) | (word32)hashID[3]; } #endif /* !NO_CERTS || !NO_SESSION_CACHE */ #ifndef NO_CERTS /* hash is the SHA digest of name, just use first 32 bits as hash */ static WC_INLINE word32 HashSigner(const byte* hash) { return MakeWordFromHash(hash) % CA_TABLE_SIZE; } /* does CA already exist on signer list */ int AlreadySigner(WOLFSSL_CERT_MANAGER* cm, byte* hash) { Signer* signers; int ret = 0; word32 row; if (cm == NULL || hash == NULL) { return ret; } row = HashSigner(hash); if (wc_LockMutex(&cm->caLock) != 0) { return ret; } signers = cm->caTable[row]; while (signers) { byte* subjectHash; #ifndef NO_SKID subjectHash = signers->subjectKeyIdHash; #else subjectHash = signers->subjectNameHash; #endif if (XMEMCMP(hash, subjectHash, SIGNER_DIGEST_SIZE) == 0) { ret = 1; /* success */ break; } signers = signers->next; } wc_UnLockMutex(&cm->caLock); return ret; } #ifdef WOLFSSL_TRUST_PEER_CERT /* hash is the SHA digest of name, just use first 32 bits as hash */ static WC_INLINE word32 TrustedPeerHashSigner(const byte* hash) { return MakeWordFromHash(hash) % TP_TABLE_SIZE; } /* does trusted peer already exist on signer list */ int AlreadyTrustedPeer(WOLFSSL_CERT_MANAGER* cm, DecodedCert* cert) { TrustedPeerCert* tp; int ret = 0; word32 row = TrustedPeerHashSigner(cert->subjectHash); if (wc_LockMutex(&cm->tpLock) != 0) return ret; tp = cm->tpTable[row]; while (tp) { if (XMEMCMP(cert->subjectHash, tp->subjectNameHash, SIGNER_DIGEST_SIZE) == 0) ret = 1; #ifndef NO_SKID if (cert->extSubjKeyIdSet) { /* Compare SKID as well if available */ if (ret == 1 && XMEMCMP(cert->extSubjKeyId, tp->subjectKeyIdHash, SIGNER_DIGEST_SIZE) != 0) ret = 0; } #endif if (ret == 1) break; tp = tp->next; } wc_UnLockMutex(&cm->tpLock); return ret; } /* return Trusted Peer if found, otherwise NULL type is what to match on */ TrustedPeerCert* GetTrustedPeer(void* vp, DecodedCert* cert) { WOLFSSL_CERT_MANAGER* cm = (WOLFSSL_CERT_MANAGER*)vp; TrustedPeerCert* ret = NULL; TrustedPeerCert* tp = NULL; word32 row; if (cm == NULL || cert == NULL) return NULL; row = TrustedPeerHashSigner(cert->subjectHash); if (wc_LockMutex(&cm->tpLock) != 0) return ret; tp = cm->tpTable[row]; while (tp) { if (XMEMCMP(cert->subjectHash, tp->subjectNameHash, SIGNER_DIGEST_SIZE) == 0) ret = tp; #ifndef NO_SKID if (cert->extSubjKeyIdSet) { /* Compare SKID as well if available */ if (ret != NULL && XMEMCMP(cert->extSubjKeyId, tp->subjectKeyIdHash, SIGNER_DIGEST_SIZE) != 0) ret = NULL; } #endif if (ret != NULL) break; tp = tp->next; } wc_UnLockMutex(&cm->tpLock); return ret; } int MatchTrustedPeer(TrustedPeerCert* tp, DecodedCert* cert) { if (tp == NULL || cert == NULL) return BAD_FUNC_ARG; /* subject key id or subject hash has been compared when searching tpTable for the cert from function GetTrustedPeer */ /* compare signatures */ if (tp->sigLen == cert->sigLength) { if (XMEMCMP(tp->sig, cert->signature, cert->sigLength)) { return WOLFSSL_FAILURE; } } else { return WOLFSSL_FAILURE; } return WOLFSSL_SUCCESS; } #endif /* WOLFSSL_TRUST_PEER_CERT */ /* return CA if found, otherwise NULL */ Signer* GetCA(void* vp, byte* hash) { WOLFSSL_CERT_MANAGER* cm = (WOLFSSL_CERT_MANAGER*)vp; Signer* ret = NULL; Signer* signers; word32 row = 0; if (cm == NULL || hash == NULL) return NULL; row = HashSigner(hash); if (wc_LockMutex(&cm->caLock) != 0) return ret; signers = cm->caTable[row]; while (signers) { byte* subjectHash; #ifndef NO_SKID subjectHash = signers->subjectKeyIdHash; #else subjectHash = signers->subjectNameHash; #endif if (XMEMCMP(hash, subjectHash, SIGNER_DIGEST_SIZE) == 0) { ret = signers; break; } signers = signers->next; } wc_UnLockMutex(&cm->caLock); return ret; } #ifndef NO_SKID /* return CA if found, otherwise NULL. Walk through hash table. */ Signer* GetCAByName(void* vp, byte* hash) { WOLFSSL_CERT_MANAGER* cm = (WOLFSSL_CERT_MANAGER*)vp; Signer* ret = NULL; Signer* signers; word32 row; if (cm == NULL) return NULL; if (wc_LockMutex(&cm->caLock) != 0) return ret; for (row = 0; row < CA_TABLE_SIZE && ret == NULL; row++) { signers = cm->caTable[row]; while (signers && ret == NULL) { if (XMEMCMP(hash, signers->subjectNameHash, SIGNER_DIGEST_SIZE) == 0) { ret = signers; } signers = signers->next; } } wc_UnLockMutex(&cm->caLock); return ret; } #endif #ifdef WOLFSSL_TRUST_PEER_CERT /* add a trusted peer cert to linked list */ int AddTrustedPeer(WOLFSSL_CERT_MANAGER* cm, DerBuffer** pDer, int verify) { int ret, row; TrustedPeerCert* peerCert; DecodedCert* cert; DerBuffer* der = *pDer; WOLFSSL_MSG("Adding a Trusted Peer Cert"); cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), cm->heap, DYNAMIC_TYPE_DCERT); if (cert == NULL) { FreeDer(&der); return MEMORY_E; } InitDecodedCert(cert, der->buffer, der->length, cm->heap); if ((ret = ParseCert(cert, TRUSTED_PEER_TYPE, verify, cm)) != 0) { FreeDecodedCert(cert); XFREE(cert, NULL, DYNAMIC_TYPE_DCERT); FreeDer(&der); return ret; } WOLFSSL_MSG("\tParsed new trusted peer cert"); peerCert = (TrustedPeerCert*)XMALLOC(sizeof(TrustedPeerCert), cm->heap, DYNAMIC_TYPE_CERT); if (peerCert == NULL) { FreeDecodedCert(cert); XFREE(cert, cm->heap, DYNAMIC_TYPE_DCERT); FreeDer(&der); return MEMORY_E; } XMEMSET(peerCert, 0, sizeof(TrustedPeerCert)); #ifndef IGNORE_NAME_CONSTRAINTS if (peerCert->permittedNames) FreeNameSubtrees(peerCert->permittedNames, cm->heap); if (peerCert->excludedNames) FreeNameSubtrees(peerCert->excludedNames, cm->heap); #endif if (AlreadyTrustedPeer(cm, cert)) { WOLFSSL_MSG("\tAlready have this CA, not adding again"); FreeTrustedPeer(peerCert, cm->heap); (void)ret; } else { /* add trusted peer signature */ peerCert->sigLen = cert->sigLength; peerCert->sig = (byte *)XMALLOC(cert->sigLength, cm->heap, DYNAMIC_TYPE_SIGNATURE); if (peerCert->sig == NULL) { FreeDecodedCert(cert); XFREE(cert, cm->heap, DYNAMIC_TYPE_DCERT); FreeTrustedPeer(peerCert, cm->heap); FreeDer(&der); return MEMORY_E; } XMEMCPY(peerCert->sig, cert->signature, cert->sigLength); /* add trusted peer name */ peerCert->nameLen = cert->subjectCNLen; peerCert->name = cert->subjectCN; #ifndef IGNORE_NAME_CONSTRAINTS peerCert->permittedNames = cert->permittedNames; peerCert->excludedNames = cert->excludedNames; #endif /* add SKID when available and hash of name */ #ifndef NO_SKID XMEMCPY(peerCert->subjectKeyIdHash, cert->extSubjKeyId, SIGNER_DIGEST_SIZE); #endif XMEMCPY(peerCert->subjectNameHash, cert->subjectHash, SIGNER_DIGEST_SIZE); peerCert->next = NULL; /* If Key Usage not set, all uses valid. */ cert->subjectCN = 0; #ifndef IGNORE_NAME_CONSTRAINTS cert->permittedNames = NULL; cert->excludedNames = NULL; #endif row = TrustedPeerHashSigner(peerCert->subjectNameHash); if (wc_LockMutex(&cm->tpLock) == 0) { peerCert->next = cm->tpTable[row]; cm->tpTable[row] = peerCert; /* takes ownership */ wc_UnLockMutex(&cm->tpLock); } else { WOLFSSL_MSG("\tTrusted Peer Cert Mutex Lock failed"); FreeDecodedCert(cert); XFREE(cert, cm->heap, DYNAMIC_TYPE_DCERT); FreeTrustedPeer(peerCert, cm->heap); FreeDer(&der); return BAD_MUTEX_E; } } WOLFSSL_MSG("\tFreeing parsed trusted peer cert"); FreeDecodedCert(cert); XFREE(cert, cm->heap, DYNAMIC_TYPE_DCERT); WOLFSSL_MSG("\tFreeing der trusted peer cert"); FreeDer(&der); WOLFSSL_MSG("\t\tOK Freeing der trusted peer cert"); WOLFSSL_LEAVE("AddTrustedPeer", ret); return WOLFSSL_SUCCESS; } #endif /* WOLFSSL_TRUST_PEER_CERT */ /* owns der, internal now uses too */ /* type flag ids from user or from chain received during verify don't allow chain ones to be added w/o isCA extension */ int AddCA(WOLFSSL_CERT_MANAGER* cm, DerBuffer** pDer, int type, int verify) { int ret; Signer* signer = NULL; word32 row; byte* subjectHash; #ifdef WOLFSSL_SMALL_STACK DecodedCert* cert = NULL; #else DecodedCert cert[1]; #endif DerBuffer* der = *pDer; WOLFSSL_MSG("Adding a CA"); if (cm == NULL) { FreeDer(pDer); return BAD_FUNC_ARG; } #ifdef WOLFSSL_SMALL_STACK cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, DYNAMIC_TYPE_DCERT); if (cert == NULL) { FreeDer(pDer); return MEMORY_E; } #endif InitDecodedCert(cert, der->buffer, der->length, cm->heap); ret = ParseCert(cert, CA_TYPE, verify, cm); WOLFSSL_MSG("\tParsed new CA"); #ifndef NO_SKID subjectHash = cert->extSubjKeyId; #else subjectHash = cert->subjectHash; #endif /* check CA key size */ if (verify) { switch (cert->keyOID) { #ifndef NO_RSA case RSAk: if (cm->minRsaKeySz < 0 || cert->pubKeySize < (word16)cm->minRsaKeySz) { ret = RSA_KEY_SIZE_E; WOLFSSL_MSG("\tCA RSA key size error"); } break; #endif /* !NO_RSA */ #ifdef HAVE_ECC case ECDSAk: if (cm->minEccKeySz < 0 || cert->pubKeySize < (word16)cm->minEccKeySz) { ret = ECC_KEY_SIZE_E; WOLFSSL_MSG("\tCA ECC key size error"); } break; #endif /* HAVE_ECC */ #ifdef HAVE_ED25519 case ED25519k: if (cm->minEccKeySz < 0 || ED25519_KEY_SIZE < (word16)cm->minEccKeySz) { ret = ECC_KEY_SIZE_E; WOLFSSL_MSG("\tCA ECC key size error"); } break; #endif /* HAVE_ED25519 */ #ifdef HAVE_ED448 case ED448k: if (cm->minEccKeySz < 0 || ED448_KEY_SIZE < (word16)cm->minEccKeySz) { ret = ECC_KEY_SIZE_E; WOLFSSL_MSG("\tCA ECC key size error"); } break; #endif /* HAVE_ED448 */ #if defined(HAVE_PQC) && defined(HAVE_FALCON) case FALCON_LEVEL1k: if (cm->minFalconKeySz < 0 || FALCON_LEVEL1_KEY_SIZE < (word16)cm->minFalconKeySz) { ret = FALCON_KEY_SIZE_E; WOLFSSL_MSG("\tCA Falcon level 1 key size error"); } break; case FALCON_LEVEL5k: if (cm->minFalconKeySz < 0 || FALCON_LEVEL5_KEY_SIZE < (word16)cm->minFalconKeySz) { ret = FALCON_KEY_SIZE_E; WOLFSSL_MSG("\tCA Falcon level 5 key size error"); } break; #endif /* HAVE_PQC && HAVE_FALCON */ default: WOLFSSL_MSG("\tNo key size check done on CA"); break; /* no size check if key type is not in switch */ } } if (ret == 0 && cert->isCA == 0 && type != WOLFSSL_USER_CA) { WOLFSSL_MSG("\tCan't add as CA if not actually one"); ret = NOT_CA_ERROR; } #ifndef ALLOW_INVALID_CERTSIGN else if (ret == 0 && cert->isCA == 1 && type != WOLFSSL_USER_CA && !cert->selfSigned && (cert->extKeyUsage & KEYUSE_KEY_CERT_SIGN) == 0) { /* Intermediate CA certs are required to have the keyCertSign * extension set. User loaded root certs are not. */ WOLFSSL_MSG("\tDoesn't have key usage certificate signing"); ret = NOT_CA_ERROR; } #endif else if (ret == 0 && AlreadySigner(cm, subjectHash)) { WOLFSSL_MSG("\tAlready have this CA, not adding again"); (void)ret; } else if (ret == 0) { /* take over signer parts */ signer = MakeSigner(cm->heap); if (!signer) ret = MEMORY_ERROR; } if (ret == 0 && signer != NULL) { #ifdef WOLFSSL_SIGNER_DER_CERT ret = AllocDer(&signer->derCert, der->length, der->type, NULL); } if (ret == 0 && signer != NULL) { XMEMCPY(signer->derCert->buffer, der->buffer, der->length); #endif signer->keyOID = cert->keyOID; if (cert->pubKeyStored) { signer->publicKey = cert->publicKey; signer->pubKeySize = cert->pubKeySize; } if (cert->subjectCNStored) { signer->nameLen = cert->subjectCNLen; signer->name = cert->subjectCN; } signer->pathLength = cert->pathLength; signer->maxPathLen = cert->maxPathLen; signer->pathLengthSet = cert->pathLengthSet; signer->selfSigned = cert->selfSigned; #ifndef IGNORE_NAME_CONSTRAINTS signer->permittedNames = cert->permittedNames; signer->excludedNames = cert->excludedNames; #endif #ifndef NO_SKID XMEMCPY(signer->subjectKeyIdHash, cert->extSubjKeyId, SIGNER_DIGEST_SIZE); #endif XMEMCPY(signer->subjectNameHash, cert->subjectHash, SIGNER_DIGEST_SIZE); #ifdef HAVE_OCSP XMEMCPY(signer->subjectKeyHash, cert->subjectKeyHash, KEYID_SIZE); #endif signer->keyUsage = cert->extKeyUsageSet ? cert->extKeyUsage : 0xFFFF; signer->next = NULL; /* If Key Usage not set, all uses valid. */ cert->publicKey = 0; /* in case lock fails don't free here. */ cert->subjectCN = 0; #ifndef IGNORE_NAME_CONSTRAINTS cert->permittedNames = NULL; cert->excludedNames = NULL; #endif #ifndef NO_SKID row = HashSigner(signer->subjectKeyIdHash); #else row = HashSigner(signer->subjectNameHash); #endif if (wc_LockMutex(&cm->caLock) == 0) { signer->next = cm->caTable[row]; cm->caTable[row] = signer; /* takes ownership */ wc_UnLockMutex(&cm->caLock); if (cm->caCacheCallback) cm->caCacheCallback(der->buffer, (int)der->length, type); } else { WOLFSSL_MSG("\tCA Mutex Lock failed"); ret = BAD_MUTEX_E; FreeSigner(signer, cm->heap); } } #if defined(WOLFSSL_RENESAS_TSIP_TLS) || defined(WOLFSSL_RENESAS_SCEPROTECT) /* Verify CA by TSIP so that generated tsip key is going to be able to */ /* be used for peer's cert verification */ /* TSIP is only able to handle USER CA, and only one CA. */ /* Therefore, it doesn't need to call TSIP again if there is already */ /* verified CA. */ if ( ret == 0 && signer != NULL ) { signer->cm_idx = row; if (type == WOLFSSL_USER_CA) { if ((ret = wc_Renesas_cmn_RootCertVerify(cert->source, cert->maxIdx, cert->sigCtx.CertAtt.pubkey_n_start, cert->sigCtx.CertAtt.pubkey_n_len - 1, cert->sigCtx.CertAtt.pubkey_e_start, cert->sigCtx.CertAtt.pubkey_e_len - 1, row/* cm index */)) < 0) WOLFSSL_MSG("Renesas_RootCertVerify() failed"); else WOLFSSL_MSG("Renesas_RootCertVerify() succeed or skipped"); } } #endif /* TSIP or SCE */ WOLFSSL_MSG("\tFreeing Parsed CA"); FreeDecodedCert(cert); #ifdef WOLFSSL_SMALL_STACK XFREE(cert, NULL, DYNAMIC_TYPE_DCERT); #endif WOLFSSL_MSG("\tFreeing der CA"); FreeDer(pDer); WOLFSSL_MSG("\t\tOK Freeing der CA"); WOLFSSL_LEAVE("AddCA", ret); return ret == 0 ? WOLFSSL_SUCCESS : ret; } #endif /* !NO_CERTS */ #ifndef NO_SESSION_CACHE /* basic config gives a cache with 33 sessions, adequate for clients and embedded servers TITAN_SESSION_CACHE allows just over 2 million sessions, for servers with titanic amounts of memory with long session ID timeouts and high levels of traffic. ENABLE_SESSION_CACHE_ROW_LOCK: Allows row level locking for increased performance with large session caches HUGE_SESSION_CACHE yields 65,791 sessions, for servers under heavy load, allows over 13,000 new sessions per minute or over 200 new sessions per second BIG_SESSION_CACHE yields 20,027 sessions MEDIUM_SESSION_CACHE allows 1055 sessions, adequate for servers that aren't under heavy load, basically allows 200 new sessions per minute SMALL_SESSION_CACHE only stores 6 sessions, good for embedded clients or systems where the default of nearly 3kB is too much RAM, this define uses less than 500 bytes RAM default SESSION_CACHE stores 33 sessions (no XXX_SESSION_CACHE defined) */ #if defined(TITAN_SESSION_CACHE) #define SESSIONS_PER_ROW 31 #define SESSION_ROWS 64937 #ifdef ENABLE_SESSION_CACHE_ROW_LOCK #define ENABLE_SESSION_CACHE_ROW_LOCK #endif #elif defined(HUGE_SESSION_CACHE) #define SESSIONS_PER_ROW 11 #define SESSION_ROWS 5981 #elif defined(BIG_SESSION_CACHE) #define SESSIONS_PER_ROW 7 #define SESSION_ROWS 2861 #elif defined(MEDIUM_SESSION_CACHE) #define SESSIONS_PER_ROW 5 #define SESSION_ROWS 211 #elif defined(SMALL_SESSION_CACHE) #define SESSIONS_PER_ROW 2 #define SESSION_ROWS 3 #else #define SESSIONS_PER_ROW 3 #define SESSION_ROWS 11 #endif #define INVALID_SESSION_ROW (-1) #ifdef NO_SESSION_CACHE_ROW_LOCK #undef ENABLE_SESSION_CACHE_ROW_LOCK #endif typedef struct SessionRow { int nextIdx; /* where to place next one */ int totalCount; /* sessions ever on this row */ WOLFSSL_SESSION Sessions[SESSIONS_PER_ROW]; #ifdef ENABLE_SESSION_CACHE_ROW_LOCK /* not included in import/export */ wolfSSL_Mutex row_mutex; int mutex_valid; #endif } SessionRow; #define SIZEOF_SESSION_ROW (sizeof(WOLFSSL_SESSION) + (sizeof(int) * 2)) static WOLFSSL_GLOBAL SessionRow SessionCache[SESSION_ROWS]; #if defined(WOLFSSL_SESSION_STATS) && defined(WOLFSSL_PEAK_SESSIONS) static WOLFSSL_GLOBAL word32 PeakSessions; #endif #ifdef ENABLE_SESSION_CACHE_ROW_LOCK #define SESSION_ROW_LOCK(row) wc_LockMutex(&(row)->row_mutex) #define SESSION_ROW_UNLOCK(row) wc_UnLockMutex(&(row)->row_mutex); #else static WOLFSSL_GLOBAL wolfSSL_Mutex session_mutex; /* SessionCache mutex */ static WOLFSSL_GLOBAL int session_mutex_valid = 0; #define SESSION_ROW_LOCK(row) wc_LockMutex(&session_mutex) #define SESSION_ROW_UNLOCK(row) wc_UnLockMutex(&session_mutex); #endif #if !defined(NO_SESSION_CACHE_REF) && defined(NO_CLIENT_CACHE) #error ClientCache is required when not using NO_SESSION_CACHE_REF #endif #ifndef NO_CLIENT_CACHE #ifndef CLIENT_SESSIONS_MULTIPLIER #ifdef NO_SESSION_CACHE_REF #define CLIENT_SESSIONS_MULTIPLIER 1 #else /* ClientSession objects are lightweight (compared to * WOLFSSL_SESSION) so to decrease chance that user will reuse * thse wrong session, increase the ClientCache size. This will * make the entire ClientCache about the size of one * WOLFSSL_SESSION object. */ #define CLIENT_SESSIONS_MULTIPLIER 8 #endif #endif #define CLIENT_SESSIONS_PER_ROW \ (SESSIONS_PER_ROW * CLIENT_SESSIONS_MULTIPLIER) #define CLIENT_SESSION_ROWS (SESSION_ROWS * CLIENT_SESSIONS_MULTIPLIER) #if CLIENT_SESSIONS_PER_ROW > 65535 #error CLIENT_SESSIONS_PER_ROW too big #endif #if CLIENT_SESSION_ROWS > 65535 #error CLIENT_SESSION_ROWS too big #endif struct ClientSession { word16 serverRow; /* SessionCache Row id */ word16 serverIdx; /* SessionCache Idx (column) */ word32 sessionIDHash; }; #ifndef WOLFSSL_CLIENT_SESSION_DEFINED typedef struct ClientSession ClientSession; #define WOLFSSL_CLIENT_SESSION_DEFINED #endif typedef struct ClientRow { int nextIdx; /* where to place next one */ int totalCount; /* sessions ever on this row */ ClientSession Clients[CLIENT_SESSIONS_PER_ROW]; } ClientRow; static WOLFSSL_GLOBAL ClientRow ClientCache[CLIENT_SESSION_ROWS]; /* Client Cache */ /* uses session mutex */ static WOLFSSL_GLOBAL wolfSSL_Mutex clisession_mutex; /* ClientCache mutex */ static WOLFSSL_GLOBAL int clisession_mutex_valid = 0; #endif /* !NO_CLIENT_CACHE */ #endif /* !NO_SESSION_CACHE */ #if !defined(WC_NO_RNG) && (defined(OPENSSL_EXTRA) || \ (defined(OPENSSL_EXTRA_X509_SMALL) && !defined(NO_RSA))) #define HAVE_GLOBAL_RNG /* consolidate flags for using globalRNG */ static WC_RNG globalRNG; static int initGlobalRNG = 0; static wolfSSL_Mutex globalRNGMutex; static int globalRNGMutex_valid = 0; #if defined(OPENSSL_EXTRA) && defined(HAVE_HASHDRBG) static WOLFSSL_DRBG_CTX* gDrbgDefCtx = NULL; #endif WC_RNG* wolfssl_get_global_rng(void) { WC_RNG* ret = NULL; if (initGlobalRNG == 0) WOLFSSL_MSG("Global RNG no Init"); else ret = &globalRNG; return ret; } #endif #if defined(OPENSSL_EXTRA) && !defined(WOLFSSL_NO_OPENSSL_RAND_CB) static int wolfSSL_RAND_InitMutex(void); #endif #if defined(OPENSSL_EXTRA) && defined(HAVE_ATEXIT) static void AtExitCleanup(void) { if (initRefCount > 0) { initRefCount = 1; (void)wolfSSL_Cleanup(); } } #endif WOLFSSL_ABI int wolfSSL_Init(void) { int ret = WOLFSSL_SUCCESS; #if !defined(NO_SESSION_CACHE) && defined(ENABLE_SESSION_CACHE_ROW_LOCK) int i; #endif WOLFSSL_ENTER("wolfSSL_Init"); #if FIPS_VERSION_GE(5,1) ret = wolfCrypt_SetPrivateKeyReadEnable_fips(1, WC_KEYTYPE_ALL); if (ret != 0) return ret; else ret = WOLFSSL_SUCCESS; #endif if (initRefCount == 0) { /* Initialize crypto for use with TLS connection */ if (wolfCrypt_Init() != 0) { WOLFSSL_MSG("Bad wolfCrypt Init"); ret = WC_INIT_E; } #ifdef HAVE_GLOBAL_RNG if ((ret == WOLFSSL_SUCCESS) && (wc_InitMutex(&globalRNGMutex) != 0)) { WOLFSSL_MSG("Bad Init Mutex rng"); ret = BAD_MUTEX_E; } else { globalRNGMutex_valid = 1; } #endif #ifdef WC_RNG_SEED_CB wc_SetSeed_Cb(wc_GenerateSeed); #endif #ifdef OPENSSL_EXTRA #ifndef WOLFSSL_NO_OPENSSL_RAND_CB if ((ret == WOLFSSL_SUCCESS) && (wolfSSL_RAND_InitMutex() != 0)) { ret = BAD_MUTEX_E; } #endif if ((ret == WOLFSSL_SUCCESS) && (wolfSSL_RAND_seed(NULL, 0) != WOLFSSL_SUCCESS)) { WOLFSSL_MSG("wolfSSL_RAND_Seed failed"); ret = WC_INIT_E; } #endif #ifndef NO_SESSION_CACHE #ifdef ENABLE_SESSION_CACHE_ROW_LOCK for (i = 0; i < SESSION_ROWS; ++i) { SessionCache[i].mutex_valid = 0; } for (i = 0; (ret == WOLFSSL_SUCCESS) && (i < SESSION_ROWS); ++i) { if (wc_InitMutex(&SessionCache[i].row_mutex) != 0) { WOLFSSL_MSG("Bad Init Mutex session"); ret = BAD_MUTEX_E; } else { SessionCache[i].mutex_valid = 1; } } #else if ((ret == WOLFSSL_SUCCESS) && (wc_InitMutex(&session_mutex) != 0)) { WOLFSSL_MSG("Bad Init Mutex session"); ret = BAD_MUTEX_E; } else { session_mutex_valid = 1; } #endif #ifndef NO_CLIENT_CACHE if ((ret == WOLFSSL_SUCCESS) && (wc_InitMutex(&clisession_mutex) != 0)) { WOLFSSL_MSG("Bad Init Mutex session"); ret = BAD_MUTEX_E; } else { clisession_mutex_valid = 1; } #endif #endif if ((ret == WOLFSSL_SUCCESS) && (wc_InitMutex(&count_mutex) != 0)) { WOLFSSL_MSG("Bad Init Mutex count"); ret = BAD_MUTEX_E; } else { count_mutex_valid = 1; } #if defined(OPENSSL_EXTRA) && defined(HAVE_ATEXIT) /* OpenSSL registers cleanup using atexit */ if ((ret == WOLFSSL_SUCCESS) && (atexit(AtExitCleanup) != 0)) { WOLFSSL_MSG("Bad atexit registration"); ret = WC_INIT_E; } #endif } if ((ret == WOLFSSL_SUCCESS) && (wc_LockMutex(&count_mutex) != 0)) { WOLFSSL_MSG("Bad Lock Mutex count"); ret = BAD_MUTEX_E; } else { initRefCount++; wc_UnLockMutex(&count_mutex); } if (ret != WOLFSSL_SUCCESS) { initRefCount = 1; /* Force cleanup */ (void)wolfSSL_Cleanup(); /* Ignore any error from cleanup */ } return ret; } #ifndef NO_CERTS /* process user cert chain to pass during the handshake */ static int ProcessUserChain(WOLFSSL_CTX* ctx, const unsigned char* buff, long sz, int format, int type, WOLFSSL* ssl, long* used, EncryptedInfo* info, int verify) { int ret = 0; void* heap = wolfSSL_CTX_GetHeap(ctx, ssl); #ifdef WOLFSSL_TLS13 int cnt = 0; #endif if ((type == CA_TYPE) && (ctx == NULL)) { WOLFSSL_MSG("Need context for CA load"); return BAD_FUNC_ARG; } /* we may have a user cert chain, try to consume */ if ((type == CERT_TYPE || type == CA_TYPE) && (info->consumed < sz)) { #ifdef WOLFSSL_SMALL_STACK byte staticBuffer[1]; /* force heap usage */ #else byte staticBuffer[FILE_BUFFER_SIZE]; /* tmp chain buffer */ #endif byte* chainBuffer = staticBuffer; int dynamicBuffer = 0; word32 bufferSz; long consumed = info->consumed; word32 idx = 0; int gotOne = 0; /* Calculate max possible size, including max headers */ bufferSz = (word32)(sz - consumed) + (CERT_HEADER_SZ * MAX_CHAIN_DEPTH); if (bufferSz > sizeof(staticBuffer)) { WOLFSSL_MSG("Growing Tmp Chain Buffer"); /* will shrink to actual size */ chainBuffer = (byte*)XMALLOC(bufferSz, heap, DYNAMIC_TYPE_FILE); if (chainBuffer == NULL) { return MEMORY_E; } dynamicBuffer = 1; } WOLFSSL_MSG("Processing Cert Chain"); while (consumed < sz) { DerBuffer* part = NULL; word32 remain = (word32)(sz - consumed); info->consumed = 0; if (format == WOLFSSL_FILETYPE_PEM) { #ifdef WOLFSSL_PEM_TO_DER ret = PemToDer(buff + consumed, remain, type, &part, heap, info, NULL); #else ret = NOT_COMPILED_IN; #endif } else { int length = remain; if (format == WOLFSSL_FILETYPE_ASN1) { /* get length of der (read sequence) */ word32 inOutIdx = 0; if (GetSequence(buff + consumed, &inOutIdx, &length, remain) < 0) { ret = ASN_NO_PEM_HEADER; } length += inOutIdx; /* include leading sequence */ } info->consumed = length; if (ret == 0) { ret = AllocDer(&part, length, type, heap); if (ret == 0) { XMEMCPY(part->buffer, buff + consumed, length); } } } if (ret == 0) { gotOne = 1; #ifdef WOLFSSL_TLS13 cnt++; #endif if ((idx + part->length + CERT_HEADER_SZ) > bufferSz) { WOLFSSL_MSG(" Cert Chain bigger than buffer. " "Consider increasing MAX_CHAIN_DEPTH"); ret = BUFFER_E; } else { c32to24(part->length, &chainBuffer[idx]); idx += CERT_HEADER_SZ; XMEMCPY(&chainBuffer[idx], part->buffer, part->length); idx += part->length; consumed += info->consumed; if (used) *used += info->consumed; } /* add CA's to certificate manager */ if (ret == 0 && type == CA_TYPE) { /* verify CA unless user set to no verify */ ret = AddCA(ctx->cm, &part, WOLFSSL_USER_CA, verify); if (ret == WOLFSSL_SUCCESS) { ret = 0; /* converted success case */ } gotOne = 0; /* don't exit loop for CA type */ } } FreeDer(&part); if (ret == ASN_NO_PEM_HEADER && gotOne) { WOLFSSL_MSG("We got one good cert, so stuff at end ok"); break; } if (ret < 0) { WOLFSSL_MSG(" Error in Cert in Chain"); if (dynamicBuffer) XFREE(chainBuffer, heap, DYNAMIC_TYPE_FILE); return ret; } WOLFSSL_MSG(" Consumed another Cert in Chain"); } WOLFSSL_MSG("Finished Processing Cert Chain"); /* only retain actual size used */ ret = 0; if (idx > 0) { if (ssl) { if (ssl->buffers.weOwnCertChain) { FreeDer(&ssl->buffers.certChain); } ret = AllocDer(&ssl->buffers.certChain, idx, type, heap); if (ret == 0) { XMEMCPY(ssl->buffers.certChain->buffer, chainBuffer, idx); ssl->buffers.weOwnCertChain = 1; } #ifdef WOLFSSL_TLS13 ssl->buffers.certChainCnt = cnt; #endif } else if (ctx) { FreeDer(&ctx->certChain); ret = AllocDer(&ctx->certChain, idx, type, heap); if (ret == 0) { XMEMCPY(ctx->certChain->buffer, chainBuffer, idx); } #ifdef WOLFSSL_TLS13 ctx->certChainCnt = cnt; #endif } } if (dynamicBuffer) XFREE(chainBuffer, heap, DYNAMIC_TYPE_FILE); } return ret; } static int ProcessBufferTryDecode(WOLFSSL_CTX* ctx, WOLFSSL* ssl, DerBuffer* der, int* keySz, word32* idx, int* resetSuites, int* keyFormat, void* heap, int devId) { int ret = 0; (void)heap; (void)devId; if (ctx == NULL && ssl == NULL) return BAD_FUNC_ARG; if (!der || !keySz || !idx || !resetSuites || !keyFormat) return BAD_FUNC_ARG; #ifndef NO_RSA if ((*keyFormat == 0 || *keyFormat == RSAk)) { /* make sure RSA key can be used */ #ifdef WOLFSSL_SMALL_STACK RsaKey* key; #else RsaKey key[1]; #endif #ifdef WOLFSSL_SMALL_STACK key = (RsaKey*)XMALLOC(sizeof(RsaKey), heap, DYNAMIC_TYPE_RSA); if (key == NULL) return MEMORY_E; #endif ret = wc_InitRsaKey_ex(key, heap, devId); if (ret == 0) { *idx = 0; ret = wc_RsaPrivateKeyDecode(der->buffer, idx, key, der->length); #ifdef WOLF_PRIVATE_KEY_ID if (ret != 0 && (devId != INVALID_DEVID #ifdef HAVE_PK_CALLBACKS || wolfSSL_CTX_IsPrivatePkSet(ctx) #endif )) { /* if using crypto or PK callbacks, try public key decode */ *idx = 0; ret = wc_RsaPublicKeyDecode(der->buffer, idx, key, der->length); } #endif if (ret != 0) { #if !defined(HAVE_ECC) && !defined(HAVE_ED25519) && \ !defined(HAVE_ED448) && !defined(HAVE_PQC) WOLFSSL_MSG("RSA decode failed and other algorithms " "not enabled to try"); ret = WOLFSSL_BAD_FILE; #else ret = 0; /* continue trying other algorithms */ #endif } else { /* check that the size of the RSA key is enough */ int minRsaSz = ssl ? ssl->options.minRsaKeySz : ctx->minRsaKeySz; *keySz = wc_RsaEncryptSize((RsaKey*)key); if (*keySz < minRsaSz) { ret = RSA_KEY_SIZE_E; WOLFSSL_MSG("Private Key size too small"); } if (ssl) { ssl->buffers.keyType = rsa_sa_algo; ssl->buffers.keySz = *keySz; } else { ctx->privateKeyType = rsa_sa_algo; ctx->privateKeySz = *keySz; } *keyFormat = RSAk; if (ssl && ssl->options.side == WOLFSSL_SERVER_END) { ssl->options.haveStaticECC = 0; *resetSuites = 1; } } wc_FreeRsaKey(key); } #ifdef WOLFSSL_SMALL_STACK XFREE(key, heap, DYNAMIC_TYPE_RSA); #endif if (ret != 0) return ret; } #endif #ifdef HAVE_ECC if ((*keyFormat == 0 || *keyFormat == ECDSAk)) { /* make sure ECC key can be used */ #ifdef WOLFSSL_SMALL_STACK ecc_key* key; #else ecc_key key[1]; #endif #ifdef WOLFSSL_SMALL_STACK key = (ecc_key*)XMALLOC(sizeof(ecc_key), heap, DYNAMIC_TYPE_ECC); if (key == NULL) return MEMORY_E; #endif if (wc_ecc_init_ex(key, heap, devId) == 0) { *idx = 0; ret = wc_EccPrivateKeyDecode(der->buffer, idx, key, der->length); #ifdef WOLF_PRIVATE_KEY_ID if (ret != 0 && (devId != INVALID_DEVID #ifdef HAVE_PK_CALLBACKS || wolfSSL_CTX_IsPrivatePkSet(ctx) #endif )) { /* if using crypto or PK callbacks, try public key decode */ *idx = 0; ret = wc_EccPublicKeyDecode(der->buffer, idx, key, der->length); } #endif if (ret == 0) { /* check for minimum ECC key size and then free */ int minKeySz = ssl ? ssl->options.minEccKeySz : ctx->minEccKeySz; *keySz = wc_ecc_size(key); if (*keySz < minKeySz) { WOLFSSL_MSG("ECC private key too small"); ret = ECC_KEY_SIZE_E; } *keyFormat = ECDSAk; if (ssl) { ssl->options.haveStaticECC = 1; ssl->buffers.keyType = ecc_dsa_sa_algo; ssl->buffers.keySz = *keySz; } else { ctx->haveStaticECC = 1; ctx->privateKeyType = ecc_dsa_sa_algo; ctx->privateKeySz = *keySz; } if (ssl && ssl->options.side == WOLFSSL_SERVER_END) { *resetSuites = 1; } } else { ret = 0; /* continue trying other algorithms */ } wc_ecc_free(key); } #ifdef WOLFSSL_SMALL_STACK XFREE(key, heap, DYNAMIC_TYPE_ECC); #endif if (ret != 0) return ret; } #endif /* HAVE_ECC */ #if defined(HAVE_ED25519) && defined(HAVE_ED25519_KEY_IMPORT) if ((*keyFormat == 0 || *keyFormat == ED25519k)) { /* make sure Ed25519 key can be used */ #ifdef WOLFSSL_SMALL_STACK ed25519_key* key; #else ed25519_key key[1]; #endif #ifdef WOLFSSL_SMALL_STACK key = (ed25519_key*)XMALLOC(sizeof(ed25519_key), heap, DYNAMIC_TYPE_ED25519); if (key == NULL) return MEMORY_E; #endif ret = wc_ed25519_init_ex(key, heap, devId); if (ret == 0) { *idx = 0; ret = wc_Ed25519PrivateKeyDecode(der->buffer, idx, key, der->length); #ifdef WOLF_PRIVATE_KEY_ID if (ret != 0 && (devId != INVALID_DEVID #ifdef HAVE_PK_CALLBACKS || wolfSSL_CTX_IsPrivatePkSet(ctx) #endif )) { /* if using crypto or PK callbacks, try public key decode */ *idx = 0; ret = wc_Ed25519PublicKeyDecode(der->buffer, idx, key, der->length); } #endif if (ret == 0) { /* check for minimum key size and then free */ int minKeySz = ssl ? ssl->options.minEccKeySz : ctx->minEccKeySz; *keySz = ED25519_KEY_SIZE; if (*keySz < minKeySz) { WOLFSSL_MSG("ED25519 private key too small"); ret = ECC_KEY_SIZE_E; } if (ret == 0) { if (ssl) { ssl->buffers.keyType = ed25519_sa_algo; ssl->buffers.keySz = *keySz; } else if (ctx) { ctx->privateKeyType = ed25519_sa_algo; ctx->privateKeySz = *keySz; } *keyFormat = ED25519k; if (ssl != NULL) { /* ED25519 requires caching enabled for tracking message * hash used in EdDSA_Update for signing */ ssl->options.cacheMessages = 1; if (ssl->options.side == WOLFSSL_SERVER_END) { *resetSuites = 1; } } } } else { ret = 0; /* continue trying other algorithms */ } wc_ed25519_free(key); } #ifdef WOLFSSL_SMALL_STACK XFREE(key, heap, DYNAMIC_TYPE_ED25519); #endif if (ret != 0) return ret; } #endif /* HAVE_ED25519 && HAVE_ED25519_KEY_IMPORT */ #if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_IMPORT) if ((*keyFormat == 0 || *keyFormat == ED448k)) { /* make sure Ed448 key can be used */ #ifdef WOLFSSL_SMALL_STACK ed448_key* key = NULL; #else ed448_key key[1]; #endif #ifdef WOLFSSL_SMALL_STACK key = (ed448_key*)XMALLOC(sizeof(ed448_key), heap, DYNAMIC_TYPE_ED448); if (key == NULL) return MEMORY_E; #endif ret = wc_ed448_init(key); if (ret == 0) { *idx = 0; ret = wc_Ed448PrivateKeyDecode(der->buffer, idx, key, der->length); #ifdef WOLF_PRIVATE_KEY_ID if (ret != 0 && (devId != INVALID_DEVID #ifdef HAVE_PK_CALLBACKS || wolfSSL_CTX_IsPrivatePkSet(ctx) #endif )) { /* if using crypto or PK callbacks, try public key decode */ *idx = 0; ret = wc_Ed448PublicKeyDecode(der->buffer, idx, key, der->length); } #endif if (ret == 0) { /* check for minimum key size and then free */ int minKeySz = ssl ? ssl->options.minEccKeySz : ctx->minEccKeySz; *keySz = ED448_KEY_SIZE; if (*keySz < minKeySz) { WOLFSSL_MSG("ED448 private key too small"); ret = ECC_KEY_SIZE_E; } } if (ret == 0) { if (ssl) { ssl->buffers.keyType = ed448_sa_algo; ssl->buffers.keySz = *keySz; } else if (ctx) { ctx->privateKeyType = ed448_sa_algo; ctx->privateKeySz = *keySz; } *keyFormat = ED448k; if (ssl != NULL) { /* ED448 requires caching enabled for tracking message * hash used in EdDSA_Update for signing */ ssl->options.cacheMessages = 1; if (ssl->options.side == WOLFSSL_SERVER_END) { *resetSuites = 1; } } } wc_ed448_free(key); } #ifdef WOLFSSL_SMALL_STACK XFREE(key, heap, DYNAMIC_TYPE_ED448); #endif if (ret != 0) return ret; } #endif /* HAVE_ED448 && HAVE_ED448_KEY_IMPORT */ #if defined(HAVE_PQC) && defined(HAVE_FALCON) if (((*keyFormat == 0) || (*keyFormat == FALCON_LEVEL1k) || (*keyFormat == FALCON_LEVEL5k))) { /* make sure Falcon key can be used */ falcon_key* key = (falcon_key*)XMALLOC(sizeof(falcon_key), heap, DYNAMIC_TYPE_FALCON); if (key == NULL) { return MEMORY_E; } ret = wc_falcon_init(key); if (ret == 0) { if (*keyFormat == FALCON_LEVEL1k) { ret = wc_falcon_set_level(key, 1); } else if (*keyFormat == FALCON_LEVEL5k) { ret = wc_falcon_set_level(key, 5); } else { /* What if *keyformat is 0? We might want to do something more * graceful here. */ wc_falcon_free(key); ret = ALGO_ID_E; } } if (ret == 0) { *idx = 0; ret = wc_falcon_import_private_only(der->buffer, der->length, key); if (ret == 0) { /* check for minimum key size and then free */ int minKeySz = ssl ? ssl->options.minFalconKeySz : ctx->minFalconKeySz; *keySz = FALCON_MAX_KEY_SIZE; if (*keySz < minKeySz) { WOLFSSL_MSG("Falcon private key too small"); ret = FALCON_KEY_SIZE_E; } if (ssl) { if (*keyFormat == FALCON_LEVEL1k) { ssl->buffers.keyType = falcon_level1_sa_algo; } else { ssl->buffers.keyType = falcon_level5_sa_algo; } ssl->buffers.keySz = *keySz; } else { if (*keyFormat == FALCON_LEVEL1k) { ctx->privateKeyType = falcon_level1_sa_algo; } else { ctx->privateKeyType = falcon_level5_sa_algo; } ctx->privateKeySz = *keySz; } if (ssl && ssl->options.side == WOLFSSL_SERVER_END) { *resetSuites = 1; } } wc_falcon_free(key); } XFREE(key, heap, DYNAMIC_TYPE_FALCON); if (ret != 0) return ret; } #endif /* HAVE_PQC && HAVE_FALCON */ return ret; } /* process the buffer buff, length sz, into ctx of format and type used tracks bytes consumed, userChain specifies a user cert chain to pass during the handshake */ int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, long sz, int format, int type, WOLFSSL* ssl, long* used, int userChain, int verify) { DerBuffer* der = NULL; int ret = 0; int done = 0; int keyFormat = 0; int resetSuites = 0; void* heap = wolfSSL_CTX_GetHeap(ctx, ssl); int devId = wolfSSL_CTX_GetDevId(ctx, ssl); word32 idx = 0; int keySz = 0; #if (defined(WOLFSSL_ENCRYPTED_KEYS) && !defined(NO_PWDBASED)) || \ defined(HAVE_PKCS8) word32 algId = 0; #endif #ifdef WOLFSSL_SMALL_STACK EncryptedInfo* info = NULL; #else EncryptedInfo info[1]; #endif (void)devId; (void)idx; (void)keySz; if (used) *used = sz; /* used bytes default to sz, PEM chain may shorten*/ /* check args */ if (format != WOLFSSL_FILETYPE_ASN1 && format != WOLFSSL_FILETYPE_PEM) return WOLFSSL_BAD_FILETYPE; if (ctx == NULL && ssl == NULL) return BAD_FUNC_ARG; #ifdef WOLFSSL_SMALL_STACK info = (EncryptedInfo*)XMALLOC(sizeof(EncryptedInfo), heap, DYNAMIC_TYPE_ENCRYPTEDINFO); if (info == NULL) return MEMORY_E; #endif XMEMSET(info, 0, sizeof(EncryptedInfo)); #if defined(WOLFSSL_ENCRYPTED_KEYS) && !defined(NO_PWDBASED) if (ctx) { info->passwd_cb = ctx->passwd_cb; info->passwd_userdata = ctx->passwd_userdata; } #endif if (format == WOLFSSL_FILETYPE_PEM) { #ifdef WOLFSSL_PEM_TO_DER ret = PemToDer(buff, sz, type, &der, heap, info, &keyFormat); #else ret = NOT_COMPILED_IN; #endif } else { /* ASN1 (DER) */ int length = (int)sz; if (format == WOLFSSL_FILETYPE_ASN1) { /* get length of der (read sequence or octet string) */ word32 inOutIdx = 0; if (GetSequence(buff, &inOutIdx, &length, (word32)sz) >= 0) { length += inOutIdx; /* include leading sequence */ } /* get length using octect string (allowed for private key types) */ else if (type == PRIVATEKEY_TYPE && GetOctetString(buff, &inOutIdx, &length, (word32)sz) >= 0) { length += inOutIdx; /* include leading oct string */ } else { ret = ASN_PARSE_E; } } info->consumed = length; if (ret == 0) { ret = AllocDer(&der, (word32)length, type, heap); if (ret == 0) { XMEMCPY(der->buffer, buff, length); } #ifdef HAVE_PKCS8 /* if private key try and remove PKCS8 header */ if (type == PRIVATEKEY_TYPE) { if ((ret = ToTraditional_ex(der->buffer, der->length, &algId)) > 0) { /* Found PKCS8 header */ /* ToTraditional_ex moves buff and returns adjusted length */ der->length = ret; keyFormat = algId; } ret = 0; /* failures should be ignored */ } #endif } } if (used) { *used = info->consumed; } /* process user chain */ if (ret >= 0) { /* Chain should have server cert first, then intermediates, then root. * First certificate in chain is processed below after ProcessUserChain * and is loaded into ssl->buffers.certificate. * Remainder are processed using ProcessUserChain and are loaded into * ssl->buffers.certChain. */ if (userChain) { ret = ProcessUserChain(ctx, buff, sz, format, type, ssl, used, info, verify); if (ret == ASN_NO_PEM_HEADER) { /* Additional chain is optional */ unsigned long pemErr; CLEAR_ASN_NO_PEM_HEADER_ERROR(pemErr); ret = 0; } } } /* info is only used for private key with DER or PEM, so free now */ if (ret < 0 || type != PRIVATEKEY_TYPE) { #ifdef WOLFSSL_SMALL_STACK XFREE(info, heap, DYNAMIC_TYPE_ENCRYPTEDINFO); #endif } /* check for error */ if (ret < 0) { FreeDer(&der); done = 1; } if (done == 1) { /* No operation, just skip the next section */ } /* Handle DER owner */ else if (type == CA_TYPE) { if (ctx == NULL) { WOLFSSL_MSG("Need context for CA load"); FreeDer(&der); return BAD_FUNC_ARG; } /* verify CA unless user set to no verify */ ret = AddCA(ctx->cm, &der, WOLFSSL_USER_CA, verify); done = 1; } #ifdef WOLFSSL_TRUST_PEER_CERT else if (type == TRUSTED_PEER_TYPE) { /* add trusted peer cert. der is freed within */ if (ctx != NULL) ret = AddTrustedPeer(ctx->cm, &der, !ctx->verifyNone); else ret = AddTrustedPeer(SSL_CM(ssl), &der, !ssl->options.verifyNone); if (ret != WOLFSSL_SUCCESS) { WOLFSSL_MSG("Error adding trusted peer"); } done = 1; } #endif /* WOLFSSL_TRUST_PEER_CERT */ else if (type == CERT_TYPE) { if (ssl != NULL) { /* Make sure previous is free'd */ if (ssl->buffers.weOwnCert) { FreeDer(&ssl->buffers.certificate); #ifdef KEEP_OUR_CERT wolfSSL_X509_free(ssl->ourCert); ssl->ourCert = NULL; #endif } ssl->buffers.certificate = der; #ifdef KEEP_OUR_CERT ssl->keepCert = 1; /* hold cert for ssl lifetime */ #endif ssl->buffers.weOwnCert = 1; } else if (ctx != NULL) { FreeDer(&ctx->certificate); /* Make sure previous is free'd */ #ifdef KEEP_OUR_CERT if (ctx->ourCert) { if (ctx->ownOurCert) wolfSSL_X509_free(ctx->ourCert); ctx->ourCert = NULL; } #endif ctx->certificate = der; } } else if (type == PRIVATEKEY_TYPE) { if (ssl != NULL) { /* Make sure previous is free'd */ if (ssl->buffers.weOwnKey) { ForceZero(ssl->buffers.key->buffer, ssl->buffers.key->length); FreeDer(&ssl->buffers.key); } ssl->buffers.key = der; #ifdef WOLFSSL_CHECK_MEM_ZERO wc_MemZero_Add("SSL Buffers key", der->buffer, der->length); #endif ssl->buffers.weOwnKey = 1; } else if (ctx != NULL) { if (ctx->privateKey != NULL && ctx->privateKey->buffer != NULL) { ForceZero(ctx->privateKey->buffer, ctx->privateKey->length); } FreeDer(&ctx->privateKey); ctx->privateKey = der; #ifdef WOLFSSL_CHECK_MEM_ZERO wc_MemZero_Add("CTX private key", der->buffer, der->length); #endif } } else { FreeDer(&der); return WOLFSSL_BAD_CERTTYPE; } if (done == 1) { /* No operation, just skip the next section */ } else if (type == PRIVATEKEY_TYPE) { ret = ProcessBufferTryDecode(ctx, ssl, der, &keySz, &idx, &resetSuites, &keyFormat, heap, devId); #if defined(WOLFSSL_ENCRYPTED_KEYS) && !defined(NO_PWDBASED) /* for WOLFSSL_FILETYPE_PEM, PemToDer manages the decryption */ /* If private key type PKCS8 header wasn't already removed (algoId == 0) */ if ((ret != 0 || keyFormat == 0) && format != WOLFSSL_FILETYPE_PEM && info->passwd_cb && algId == 0) { int passwordSz = NAME_SZ; #ifndef WOLFSSL_SMALL_STACK char password[NAME_SZ]; #else char* password = (char*)XMALLOC(passwordSz, heap, DYNAMIC_TYPE_STRING); if (password == NULL) { XFREE(info, heap, DYNAMIC_TYPE_ENCRYPTEDINFO); FreeDer(&der); return MEMORY_E; } #endif /* get password */ ret = info->passwd_cb(password, passwordSz, PEM_PASS_READ, info->passwd_userdata); if (ret >= 0) { passwordSz = ret; #ifdef WOLFSSL_CHECK_MEM_ZERO wc_MemZero_Add("ProcessBuffer password", password, passwordSz); #endif /* PKCS8 decrypt */ ret = ToTraditionalEnc(der->buffer, der->length, password, passwordSz, &algId); if (ret >= 0) { ForceZero(der->buffer + ret, der->length - ret); der->length = ret; } /* ignore failures and try parsing as unencrypted */ ForceZero(password, passwordSz); } #ifdef WOLFSSL_SMALL_STACK XFREE(password, heap, DYNAMIC_TYPE_STRING); #elif defined(WOLFSSL_CHECK_MEM_ZERO) wc_MemZero_Check(password, NAME_SZ); #endif ret = ProcessBufferTryDecode(ctx, ssl, der, &keySz, &idx, &resetSuites, &keyFormat, heap, devId); } #endif /* WOLFSSL_ENCRYPTED_KEYS && !NO_PWDBASED */ #ifdef WOLFSSL_SMALL_STACK XFREE(info, heap, DYNAMIC_TYPE_ENCRYPTEDINFO); #endif if (ret != 0) return ret; if (keyFormat == 0) { #ifdef OPENSSL_EXTRA /* Reaching this point probably means that the * decryption password is wrong */ if (info->passwd_cb) EVPerr(0, EVP_R_BAD_DECRYPT); #endif WOLFSSL_ERROR(WOLFSSL_BAD_FILE); return WOLFSSL_BAD_FILE; } (void)devId; } else if (type == CERT_TYPE) { #ifdef WOLFSSL_SMALL_STACK DecodedCert* cert; #else DecodedCert cert[1]; #endif #ifdef WOLF_PRIVATE_KEY_ID int keyType = 0; #endif #ifdef WOLFSSL_SMALL_STACK cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), heap, DYNAMIC_TYPE_DCERT); if (cert == NULL) return MEMORY_E; #endif WOLFSSL_MSG("Checking cert signature type"); InitDecodedCert(cert, der->buffer, der->length, heap); if (DecodeToKey(cert, 0) < 0) { WOLFSSL_MSG("Decode to key failed"); FreeDecodedCert(cert); #ifdef WOLFSSL_SMALL_STACK XFREE(cert, heap, DYNAMIC_TYPE_DCERT); #endif return WOLFSSL_BAD_FILE; } if (ssl && ssl->options.side == WOLFSSL_SERVER_END) { resetSuites = 1; } if (ssl && ssl->ctx->haveECDSAsig) { WOLFSSL_MSG("SSL layer setting cert, CTX had ECDSA, turning off"); ssl->options.haveECDSAsig = 0; /* may turn back on next */ } switch (cert->signatureOID) { case CTC_SHAwECDSA: case CTC_SHA256wECDSA: case CTC_SHA384wECDSA: case CTC_SHA512wECDSA: case CTC_ED25519: case CTC_ED448: WOLFSSL_MSG("ECDSA/ED25519/ED448 cert signature"); if (ssl) ssl->options.haveECDSAsig = 1; else if (ctx) ctx->haveECDSAsig = 1; break; case CTC_FALCON_LEVEL1: case CTC_FALCON_LEVEL5: WOLFSSL_MSG("Falcon cert signature"); if (ssl) ssl->options.haveFalconSig = 1; else if (ctx) ctx->haveFalconSig = 1; break; default: WOLFSSL_MSG("Not ECDSA cert signature"); break; } #if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448) || \ defined(HAVE_PQC) || !defined(NO_RSA) if (ssl) { #if defined(HAVE_ECC) || defined(HAVE_ED25519) || \ (defined(HAVE_CURVE448) && defined(HAVE_ED448)) ssl->pkCurveOID = cert->pkCurveOID; #endif #ifndef WC_STRICT_SIG if (cert->keyOID == ECDSAk) { ssl->options.haveECC = 1; } #ifndef NO_RSA else if (cert->keyOID == RSAk) { ssl->options.haveRSA = 1; } #endif #ifdef HAVE_ED25519 else if (cert->keyOID == ED25519k) { ssl->options.haveECC = 1; } #endif #ifdef HAVE_ED448 else if (cert->keyOID == ED448k) { ssl->options.haveECC = 1; } #endif #ifdef HAVE_PQC else if (cert->keyOID == FALCON_LEVEL1k || cert->keyOID == FALCON_LEVEL5k) { ssl->options.haveFalconSig = 1; } #endif #else ssl->options.haveECC = ssl->options.haveECDSAsig; #endif } else if (ctx) { #if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448) ctx->pkCurveOID = cert->pkCurveOID; #endif #ifndef WC_STRICT_SIG if (cert->keyOID == ECDSAk) { ctx->haveECC = 1; } #ifndef NO_RSA else if (cert->keyOID == RSAk) { ctx->haveRSA = 1; } #endif #ifdef HAVE_ED25519 else if (cert->keyOID == ED25519k) { ctx->haveECC = 1; } #endif #ifdef HAVE_ED448 else if (cert->keyOID == ED448k) { ctx->haveECC = 1; } #endif #ifdef HAVE_PQC else if (cert->keyOID == FALCON_LEVEL1k || cert->keyOID == FALCON_LEVEL5k) { ctx->haveFalconSig = 1; } #endif #else ctx->haveECC = ctx->haveECDSAsig; #endif } #endif /* check key size of cert unless specified not to */ switch (cert->keyOID) { #ifndef NO_RSA case RSAk: #ifdef WOLF_PRIVATE_KEY_ID keyType = rsa_sa_algo; #endif /* Determine RSA key size by parsing public key */ idx = 0; ret = wc_RsaPublicKeyDecode_ex(cert->publicKey, &idx, cert->pubKeySize, NULL, (word32*)&keySz, NULL, NULL); if (ret < 0) break; if (ssl && !ssl->options.verifyNone) { if (ssl->options.minRsaKeySz < 0 || keySz < (int)ssl->options.minRsaKeySz) { ret = RSA_KEY_SIZE_E; WOLFSSL_MSG("Certificate RSA key size too small"); } } else if (ctx && !ctx->verifyNone) { if (ctx->minRsaKeySz < 0 || keySz < (int)ctx->minRsaKeySz) { ret = RSA_KEY_SIZE_E; WOLFSSL_MSG("Certificate RSA key size too small"); } } break; #endif /* !NO_RSA */ #ifdef HAVE_ECC case ECDSAk: #ifdef WOLF_PRIVATE_KEY_ID keyType = ecc_dsa_sa_algo; #endif /* Determine ECC key size based on curve */ keySz = wc_ecc_get_curve_size_from_id( wc_ecc_get_oid(cert->pkCurveOID, NULL, NULL)); if (ssl && !ssl->options.verifyNone) { if (ssl->options.minEccKeySz < 0 || keySz < (int)ssl->options.minEccKeySz) { ret = ECC_KEY_SIZE_E; WOLFSSL_MSG("Certificate ECC key size error"); } } else if (ctx && !ctx->verifyNone) { if (ctx->minEccKeySz < 0 || keySz < (int)ctx->minEccKeySz) { ret = ECC_KEY_SIZE_E; WOLFSSL_MSG("Certificate ECC key size error"); } } break; #endif /* HAVE_ECC */ #ifdef HAVE_ED25519 case ED25519k: #ifdef WOLF_PRIVATE_KEY_ID keyType = ed25519_sa_algo; #endif /* ED25519 is fixed key size */ keySz = ED25519_KEY_SIZE; if (ssl && !ssl->options.verifyNone) { if (ssl->options.minEccKeySz < 0 || keySz < (int)ssl->options.minEccKeySz) { ret = ECC_KEY_SIZE_E; WOLFSSL_MSG("Certificate Ed key size error"); } } else if (ctx && !ctx->verifyNone) { if (ctx->minEccKeySz < 0 || keySz < (int)ctx->minEccKeySz) { ret = ECC_KEY_SIZE_E; WOLFSSL_MSG("Certificate ECC key size error"); } } break; #endif /* HAVE_ED25519 */ #ifdef HAVE_ED448 case ED448k: #ifdef WOLF_PRIVATE_KEY_ID keyType = ed448_sa_algo; #endif /* ED448 is fixed key size */ keySz = ED448_KEY_SIZE; if (ssl && !ssl->options.verifyNone) { if (ssl->options.minEccKeySz < 0 || keySz < (int)ssl->options.minEccKeySz) { ret = ECC_KEY_SIZE_E; WOLFSSL_MSG("Certificate Ed key size error"); } } else if (ctx && !ctx->verifyNone) { if (ctx->minEccKeySz < 0 || keySz < (int)ctx->minEccKeySz) { ret = ECC_KEY_SIZE_E; WOLFSSL_MSG("Certificate ECC key size error"); } } break; #endif /* HAVE_ED448 */ #if defined(HAVE_PQC) && defined(HAVE_FALCON) case FALCON_LEVEL1k: case FALCON_LEVEL5k: /* Falcon is fixed key size */ keySz = FALCON_MAX_KEY_SIZE; if (ssl && !ssl->options.verifyNone) { if (ssl->options.minFalconKeySz < 0 || keySz < (int)ssl->options.minFalconKeySz) { ret = FALCON_KEY_SIZE_E; WOLFSSL_MSG("Certificate Falcon key size error"); } } else if (ctx && !ctx->verifyNone) { if (ctx->minFalconKeySz < 0 || keySz < (int)ctx->minFalconKeySz) { ret = FALCON_KEY_SIZE_E; WOLFSSL_MSG("Certificate Falcon key size error"); } } break; #endif /* HAVE_PQC && HAVE_FALCON */ default: WOLFSSL_MSG("No key size check done on certificate"); break; /* do no check if not a case for the key */ } #ifdef WOLF_PRIVATE_KEY_ID if (ssl != NULL && ssl->buffers.keyType == 0) { ssl->buffers.keyType = keyType; ssl->buffers.keySz = keySz; } else if (ctx != NULL && ctx->privateKeyType == 0) { ctx->privateKeyType = keyType; ctx->privateKeySz = keySz; } #endif FreeDecodedCert(cert); #ifdef WOLFSSL_SMALL_STACK XFREE(cert, heap, DYNAMIC_TYPE_DCERT); #endif if (ret != 0) { done = 1; } } if (done == 1) { #if !defined(NO_WOLFSSL_CM_VERIFY) && (!defined(NO_WOLFSSL_CLIENT) || \ !defined(WOLFSSL_NO_CLIENT_AUTH)) if ((type == CA_TYPE) || (type == CERT_TYPE)) { /* Call to over-ride status */ if ((ctx != NULL) && (ctx->cm != NULL) && (ctx->cm->verifyCallback != NULL)) { ret = CM_VerifyBuffer_ex(ctx->cm, buff, sz, format, (ret == WOLFSSL_SUCCESS ? 0 : ret)); } } #endif /* NO_WOLFSSL_CM_VERIFY */ return ret; } if (ssl && resetSuites) { word16 havePSK = 0; word16 haveRSA = 0; #ifndef NO_PSK if (ssl->options.havePSK) { havePSK = 1; } #endif #ifndef NO_RSA haveRSA = 1; #endif keySz = ssl->buffers.keySz; /* let's reset suites */ InitSuites(ssl->suites, ssl->version, keySz, haveRSA, havePSK, ssl->options.haveDH, ssl->options.haveECDSAsig, ssl->options.haveECC, ssl->options.haveStaticECC, ssl->options.haveFalconSig, ssl->options.haveAnon, ssl->options.side); } return WOLFSSL_SUCCESS; } /* CA PEM file for verification, may have multiple/chain certs to process */ static int ProcessChainBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, long sz, int format, int type, WOLFSSL* ssl, int verify) { long used = 0; int ret = 0; int gotOne = 0; WOLFSSL_MSG("Processing CA PEM file"); while (used < sz) { long consumed = 0; ret = ProcessBuffer(ctx, buff + used, sz - used, format, type, ssl, &consumed, 0, verify); if (ret < 0) { #if defined(WOLFSSL_WPAS) && defined(HAVE_CRL) DerBuffer* der = NULL; EncryptedInfo info; WOLFSSL_MSG("Trying a CRL"); if (PemToDer(buff + used, sz - used, CRL_TYPE, &der, NULL, &info, NULL) == 0) { WOLFSSL_MSG(" Processed a CRL"); wolfSSL_CertManagerLoadCRLBuffer(ctx->cm, der->buffer, der->length, WOLFSSL_FILETYPE_ASN1); FreeDer(&der); used += info.consumed; continue; } #endif if (consumed > 0) { /* Made progress in file */ WOLFSSL_ERROR(ret); WOLFSSL_MSG("CA Parse failed, with progress in file."); WOLFSSL_MSG("Search for other certs in file"); } else { WOLFSSL_MSG("CA Parse failed, no progress in file."); WOLFSSL_MSG("Do not continue search for other certs in file"); break; } } else { WOLFSSL_MSG(" Processed a CA"); gotOne = 1; } used += consumed; } if (gotOne) { WOLFSSL_MSG("Processed at least one valid CA. Other stuff OK"); return WOLFSSL_SUCCESS; } return ret; } static WC_INLINE WOLFSSL_METHOD* cm_pick_method(void) { #ifndef NO_WOLFSSL_CLIENT #if !defined(NO_OLD_TLS) && defined(WOLFSSL_ALLOW_SSLV3) return wolfSSLv3_client_method(); #elif !defined(NO_OLD_TLS) && defined(WOLFSSL_ALLOW_TLSV10) return wolfTLSv1_client_method(); #elif !defined(NO_OLD_TLS) return wolfTLSv1_1_client_method(); #elif !defined(WOLFSSL_NO_TLS12) return wolfTLSv1_2_client_method(); #elif defined(WOLFSSL_TLS13) return wolfTLSv1_3_client_method(); #else return NULL; #endif #elif !defined(NO_WOLFSSL_SERVER) #if !defined(NO_OLD_TLS) && defined(WOLFSSL_ALLOW_SSLV3) return wolfSSLv3_server_method(); #elif !defined(NO_OLD_TLS) && defined(WOLFSSL_ALLOW_TLSV10) return wolfTLSv1_server_method(); #elif !defined(NO_OLD_TLS) return wolfTLSv1_1_server_method(); #elif !defined(WOLFSSL_NO_TLS12) return wolfTLSv1_2_server_method(); #elif defined(WOLFSSL_TLS13) return wolfTLSv1_3_server_method(); #else return NULL; #endif #else return NULL; #endif } /* like load verify locations, 1 for success, < 0 for error */ int wolfSSL_CertManagerLoadCABuffer(WOLFSSL_CERT_MANAGER* cm, const unsigned char* in, long sz, int format) { int ret = WOLFSSL_FATAL_ERROR; WOLFSSL_CTX* tmp; WOLFSSL_ENTER("wolfSSL_CertManagerLoadCABuffer"); if (cm == NULL) { WOLFSSL_MSG("No CertManager error"); return ret; } tmp = wolfSSL_CTX_new(cm_pick_method()); if (tmp == NULL) { WOLFSSL_MSG("CTX new failed"); return ret; } /* for tmp use */ wolfSSL_CertManagerFree(tmp->cm); tmp->cm = cm; ret = wolfSSL_CTX_load_verify_buffer(tmp, in, sz, format); /* don't loose our good one */ tmp->cm = NULL; wolfSSL_CTX_free(tmp); return ret; } #ifdef HAVE_CRL int wolfSSL_CertManagerLoadCRLBuffer(WOLFSSL_CERT_MANAGER* cm, const unsigned char* buff, long sz, int type) { WOLFSSL_ENTER("wolfSSL_CertManagerLoadCRLBuffer"); if (cm == NULL) return BAD_FUNC_ARG; if (cm->crl == NULL) { if (wolfSSL_CertManagerEnableCRL(cm, 0) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("Enable CRL failed"); return WOLFSSL_FATAL_ERROR; } } return BufferLoadCRL(cm->crl, buff, sz, type, VERIFY); } int wolfSSL_CertManagerFreeCRL(WOLFSSL_CERT_MANAGER* cm) { WOLFSSL_ENTER("wolfSSL_CertManagerFreeCRL"); if (cm == NULL) return BAD_FUNC_ARG; if (cm->crl != NULL){ FreeCRL(cm->crl, 1); cm->crl = NULL; } return WOLFSSL_SUCCESS; } int wolfSSL_CTX_LoadCRLBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, long sz, int type) { WOLFSSL_ENTER("wolfSSL_CTX_LoadCRLBuffer"); if (ctx == NULL) return BAD_FUNC_ARG; return wolfSSL_CertManagerLoadCRLBuffer(ctx->cm, buff, sz, type); } int wolfSSL_LoadCRLBuffer(WOLFSSL* ssl, const unsigned char* buff, long sz, int type) { WOLFSSL_ENTER("wolfSSL_LoadCRLBuffer"); if (ssl == NULL || ssl->ctx == NULL) return BAD_FUNC_ARG; return wolfSSL_CertManagerLoadCRLBuffer(SSL_CM(ssl), buff, sz, type); } #endif /* HAVE_CRL */ /* turn on CRL if off and compiled in, set options */ int wolfSSL_CertManagerEnableCRL(WOLFSSL_CERT_MANAGER* cm, int options) { int ret = WOLFSSL_SUCCESS; (void)options; WOLFSSL_ENTER("wolfSSL_CertManagerEnableCRL"); if (cm == NULL) return BAD_FUNC_ARG; #ifdef HAVE_CRL if (cm->crl == NULL) { cm->crl = (WOLFSSL_CRL*)XMALLOC(sizeof(WOLFSSL_CRL), cm->heap, DYNAMIC_TYPE_CRL); if (cm->crl == NULL) return MEMORY_E; if (InitCRL(cm->crl, cm) != 0) { WOLFSSL_MSG("Init CRL failed"); FreeCRL(cm->crl, 1); cm->crl = NULL; return WOLFSSL_FAILURE; } #if defined(HAVE_CRL_IO) && defined(USE_WOLFSSL_IO) cm->crl->crlIOCb = EmbedCrlLookup; #endif } cm->crlEnabled = 1; if (options & WOLFSSL_CRL_CHECKALL) cm->crlCheckAll = 1; #else ret = NOT_COMPILED_IN; #endif return ret; } int wolfSSL_CertManagerDisableCRL(WOLFSSL_CERT_MANAGER* cm) { WOLFSSL_ENTER("wolfSSL_CertManagerDisableCRL"); if (cm == NULL) return BAD_FUNC_ARG; cm->crlEnabled = 0; return WOLFSSL_SUCCESS; } #ifndef NO_WOLFSSL_CM_VERIFY void wolfSSL_CertManagerSetVerify(WOLFSSL_CERT_MANAGER* cm, VerifyCallback vc) { WOLFSSL_ENTER("wolfSSL_CertManagerSetVerify"); if (cm == NULL) return; cm->verifyCallback = vc; } #endif /* NO_WOLFSSL_CM_VERIFY */ #if !defined(NO_WOLFSSL_CLIENT) || !defined(WOLFSSL_NO_CLIENT_AUTH) /* Verify the certificate, WOLFSSL_SUCCESS for ok, < 0 for error */ int CM_VerifyBuffer_ex(WOLFSSL_CERT_MANAGER* cm, const byte* buff, long sz, int format, int err_val) { int ret = 0; DerBuffer* der = NULL; #ifdef WOLFSSL_SMALL_STACK DecodedCert* cert; #else DecodedCert cert[1]; #endif WOLFSSL_ENTER("wolfSSL_CertManagerVerifyBuffer"); #ifdef WOLFSSL_SMALL_STACK cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), cm->heap, DYNAMIC_TYPE_DCERT); if (cert == NULL) return MEMORY_E; #endif if (format == WOLFSSL_FILETYPE_PEM) { #ifdef WOLFSSL_PEM_TO_DER ret = PemToDer(buff, sz, CERT_TYPE, &der, cm->heap, NULL, NULL); if (ret != 0) { FreeDer(&der); #ifdef WOLFSSL_SMALL_STACK XFREE(cert, cm->heap, DYNAMIC_TYPE_DCERT); #endif return ret; } InitDecodedCert(cert, der->buffer, der->length, cm->heap); #else ret = NOT_COMPILED_IN; #endif } else { InitDecodedCert(cert, buff, (word32)sz, cm->heap); } if (ret == 0) ret = ParseCertRelative(cert, CERT_TYPE, 1, cm); #if defined(OPENSSL_ALL) || defined(WOLFSSL_QT) /* ret needs to be self-singer error for Qt compat */ if (ret == ASN_NO_SIGNER_E && cert->selfSigned) ret = ASN_SELF_SIGNED_E; #endif #ifdef HAVE_CRL if (ret == 0 && cm->crlEnabled) ret = CheckCertCRL(cm->crl, cert); #endif #ifndef NO_WOLFSSL_CM_VERIFY /* if verify callback has been set */ if (cm->verifyCallback) { buffer certBuf; #ifdef WOLFSSL_SMALL_STACK ProcPeerCertArgs* args; args = (ProcPeerCertArgs*)XMALLOC( sizeof(ProcPeerCertArgs), cm->heap, DYNAMIC_TYPE_TMP_BUFFER); if (args == NULL) { XFREE(cert, cm->heap, DYNAMIC_TYPE_DCERT); return MEMORY_E; } #else ProcPeerCertArgs args[1]; #endif certBuf.buffer = (byte*)buff; certBuf.length = (unsigned int)sz; XMEMSET(args, 0, sizeof(ProcPeerCertArgs)); args->totalCerts = 1; args->certs = &certBuf; args->dCert = cert; args->dCertInit = 1; if (err_val != 0) { ret = err_val; } ret = DoVerifyCallback(cm, NULL, ret, args); #ifdef WOLFSSL_SMALL_STACK XFREE(args, cm->heap, DYNAMIC_TYPE_TMP_BUFFER); #endif } #else (void)err_val; #endif FreeDecodedCert(cert); FreeDer(&der); #ifdef WOLFSSL_SMALL_STACK XFREE(cert, cm->heap, DYNAMIC_TYPE_DCERT); #endif return ret == 0 ? WOLFSSL_SUCCESS : ret; } /* Verify the certificate, WOLFSSL_SUCCESS for ok, < 0 for error */ int wolfSSL_CertManagerVerifyBuffer(WOLFSSL_CERT_MANAGER* cm, const byte* buff, long sz, int format) { return CM_VerifyBuffer_ex(cm, buff, sz, format, 0); } #endif /* !NO_WOLFSSL_CLIENT || !WOLFSSL_NO_CLIENT_AUTH */ /* turn on OCSP if off and compiled in, set options */ int wolfSSL_CertManagerEnableOCSP(WOLFSSL_CERT_MANAGER* cm, int options) { int ret = WOLFSSL_SUCCESS; (void)options; WOLFSSL_ENTER("wolfSSL_CertManagerEnableOCSP"); if (cm == NULL) return BAD_FUNC_ARG; #ifdef HAVE_OCSP if (cm->ocsp == NULL) { cm->ocsp = (WOLFSSL_OCSP*)XMALLOC(sizeof(WOLFSSL_OCSP), cm->heap, DYNAMIC_TYPE_OCSP); if (cm->ocsp == NULL) return MEMORY_E; if (InitOCSP(cm->ocsp, cm) != 0) { WOLFSSL_MSG("Init OCSP failed"); FreeOCSP(cm->ocsp, 1); cm->ocsp = NULL; return WOLFSSL_FAILURE; } } cm->ocspEnabled = 1; if (options & WOLFSSL_OCSP_URL_OVERRIDE) cm->ocspUseOverrideURL = 1; if (options & WOLFSSL_OCSP_NO_NONCE) cm->ocspSendNonce = 0; else cm->ocspSendNonce = 1; if (options & WOLFSSL_OCSP_CHECKALL) cm->ocspCheckAll = 1; #ifndef WOLFSSL_USER_IO cm->ocspIOCb = EmbedOcspLookup; cm->ocspRespFreeCb = EmbedOcspRespFree; cm->ocspIOCtx = cm->heap; #endif /* WOLFSSL_USER_IO */ #else ret = NOT_COMPILED_IN; #endif return ret; } int wolfSSL_CertManagerDisableOCSP(WOLFSSL_CERT_MANAGER* cm) { WOLFSSL_ENTER("wolfSSL_CertManagerDisableOCSP"); if (cm == NULL) return BAD_FUNC_ARG; cm->ocspEnabled = 0; return WOLFSSL_SUCCESS; } /* turn on OCSP Stapling if off and compiled in, set options */ int wolfSSL_CertManagerEnableOCSPStapling(WOLFSSL_CERT_MANAGER* cm) { int ret = WOLFSSL_SUCCESS; WOLFSSL_ENTER("wolfSSL_CertManagerEnableOCSPStapling"); if (cm == NULL) return BAD_FUNC_ARG; #if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) #ifndef NO_WOLFSSL_SERVER if (cm->ocsp_stapling == NULL) { cm->ocsp_stapling = (WOLFSSL_OCSP*)XMALLOC(sizeof(WOLFSSL_OCSP), cm->heap, DYNAMIC_TYPE_OCSP); if (cm->ocsp_stapling == NULL) return MEMORY_E; if (InitOCSP(cm->ocsp_stapling, cm) != 0) { WOLFSSL_MSG("Init OCSP failed"); FreeOCSP(cm->ocsp_stapling, 1); cm->ocsp_stapling = NULL; return WOLFSSL_FAILURE; } } #ifndef WOLFSSL_USER_IO cm->ocspIOCb = EmbedOcspLookup; cm->ocspRespFreeCb = EmbedOcspRespFree; cm->ocspIOCtx = cm->heap; #endif /* WOLFSSL_USER_IO */ #endif /* NO_WOLFSSL_SERVER */ cm->ocspStaplingEnabled = 1; #else ret = NOT_COMPILED_IN; #endif return ret; } int wolfSSL_CertManagerDisableOCSPStapling(WOLFSSL_CERT_MANAGER* cm) { int ret = WOLFSSL_SUCCESS; WOLFSSL_ENTER("wolfSSL_CertManagerDisableOCSPStapling"); if (cm == NULL) return BAD_FUNC_ARG; #if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) cm->ocspStaplingEnabled = 0; #else ret = NOT_COMPILED_IN; #endif return ret; } /* require OCSP stapling response */ int wolfSSL_CertManagerEnableOCSPMustStaple(WOLFSSL_CERT_MANAGER* cm) { int ret; WOLFSSL_ENTER("wolfSSL_CertManagerEnableOCSPMustStaple"); if (cm == NULL) return BAD_FUNC_ARG; #if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) #ifndef NO_WOLFSSL_CLIENT cm->ocspMustStaple = 1; #endif ret = WOLFSSL_SUCCESS; #else ret = NOT_COMPILED_IN; #endif return ret; } int wolfSSL_CertManagerDisableOCSPMustStaple(WOLFSSL_CERT_MANAGER* cm) { int ret; WOLFSSL_ENTER("wolfSSL_CertManagerDisableOCSPMustStaple"); if (cm == NULL) return BAD_FUNC_ARG; #if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) #ifndef NO_WOLFSSL_CLIENT cm->ocspMustStaple = 0; #endif ret = WOLFSSL_SUCCESS; #else ret = NOT_COMPILED_IN; #endif return ret; } #ifdef HAVE_OCSP /* check CRL if enabled, WOLFSSL_SUCCESS */ int wolfSSL_CertManagerCheckOCSP(WOLFSSL_CERT_MANAGER* cm, byte* der, int sz) { int ret; #ifdef WOLFSSL_SMALL_STACK DecodedCert* cert = NULL; #else DecodedCert cert[1]; #endif WOLFSSL_ENTER("wolfSSL_CertManagerCheckOCSP"); if (cm == NULL) return BAD_FUNC_ARG; if (cm->ocspEnabled == 0) return WOLFSSL_SUCCESS; #ifdef WOLFSSL_SMALL_STACK cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), cm->heap, DYNAMIC_TYPE_DCERT); if (cert == NULL) return MEMORY_E; #endif InitDecodedCert(cert, der, sz, NULL); if ((ret = ParseCertRelative(cert, CERT_TYPE, VERIFY_OCSP, cm)) != 0) { WOLFSSL_MSG("ParseCert failed"); } else if ((ret = CheckCertOCSP(cm->ocsp, cert, NULL)) != 0) { WOLFSSL_MSG("CheckCertOCSP failed"); } FreeDecodedCert(cert); #ifdef WOLFSSL_SMALL_STACK XFREE(cert, cm->heap, DYNAMIC_TYPE_DCERT); #endif return ret == 0 ? WOLFSSL_SUCCESS : ret; } WOLFSSL_API int wolfSSL_CertManagerCheckOCSPResponse(WOLFSSL_CERT_MANAGER *cm, byte *response, int responseSz, buffer *responseBuffer, CertStatus *status, OcspEntry *entry, OcspRequest *ocspRequest) { int ret; WOLFSSL_ENTER("wolfSSL_CertManagerCheckOCSPResponse"); if (cm == NULL || response == NULL) return BAD_FUNC_ARG; if (cm->ocspEnabled == 0) return WOLFSSL_SUCCESS; ret = CheckOcspResponse(cm->ocsp, response, responseSz, responseBuffer, status, entry, ocspRequest); return ret == 0 ? WOLFSSL_SUCCESS : ret; } int wolfSSL_CertManagerSetOCSPOverrideURL(WOLFSSL_CERT_MANAGER* cm, const char* url) { WOLFSSL_ENTER("wolfSSL_CertManagerSetOCSPOverrideURL"); if (cm == NULL) return BAD_FUNC_ARG; XFREE(cm->ocspOverrideURL, cm->heap, DYNAMIC_TYPE_URL); if (url != NULL) { int urlSz = (int)XSTRLEN(url) + 1; cm->ocspOverrideURL = (char*)XMALLOC(urlSz, cm->heap, DYNAMIC_TYPE_URL); if (cm->ocspOverrideURL != NULL) { XMEMCPY(cm->ocspOverrideURL, url, urlSz); } else return MEMORY_E; } else cm->ocspOverrideURL = NULL; return WOLFSSL_SUCCESS; } int wolfSSL_CertManagerSetOCSP_Cb(WOLFSSL_CERT_MANAGER* cm, CbOCSPIO ioCb, CbOCSPRespFree respFreeCb, void* ioCbCtx) { WOLFSSL_ENTER("wolfSSL_CertManagerSetOCSP_Cb"); if (cm == NULL) return BAD_FUNC_ARG; cm->ocspIOCb = ioCb; cm->ocspRespFreeCb = respFreeCb; cm->ocspIOCtx = ioCbCtx; return WOLFSSL_SUCCESS; } int wolfSSL_EnableOCSP(WOLFSSL* ssl, int options) { WOLFSSL_ENTER("wolfSSL_EnableOCSP"); if (ssl) return wolfSSL_CertManagerEnableOCSP(SSL_CM(ssl), options); else return BAD_FUNC_ARG; } int wolfSSL_DisableOCSP(WOLFSSL* ssl) { WOLFSSL_ENTER("wolfSSL_DisableOCSP"); if (ssl) return wolfSSL_CertManagerDisableOCSP(SSL_CM(ssl)); else return BAD_FUNC_ARG; } int wolfSSL_EnableOCSPStapling(WOLFSSL* ssl) { WOLFSSL_ENTER("wolfSSL_EnableOCSPStapling"); if (ssl) return wolfSSL_CertManagerEnableOCSPStapling(SSL_CM(ssl)); else return BAD_FUNC_ARG; } int wolfSSL_DisableOCSPStapling(WOLFSSL* ssl) { WOLFSSL_ENTER("wolfSSL_DisableOCSPStapling"); if (ssl) return wolfSSL_CertManagerDisableOCSPStapling(SSL_CM(ssl)); else return BAD_FUNC_ARG; } int wolfSSL_SetOCSP_OverrideURL(WOLFSSL* ssl, const char* url) { WOLFSSL_ENTER("wolfSSL_SetOCSP_OverrideURL"); if (ssl) return wolfSSL_CertManagerSetOCSPOverrideURL(SSL_CM(ssl), url); else return BAD_FUNC_ARG; } int wolfSSL_SetOCSP_Cb(WOLFSSL* ssl, CbOCSPIO ioCb, CbOCSPRespFree respFreeCb, void* ioCbCtx) { WOLFSSL_ENTER("wolfSSL_SetOCSP_Cb"); if (ssl) { ssl->ocspIOCtx = ioCbCtx; /* use SSL specific ioCbCtx */ return wolfSSL_CertManagerSetOCSP_Cb(SSL_CM(ssl), ioCb, respFreeCb, NULL); } else return BAD_FUNC_ARG; } int wolfSSL_CTX_EnableOCSP(WOLFSSL_CTX* ctx, int options) { WOLFSSL_ENTER("wolfSSL_CTX_EnableOCSP"); if (ctx) return wolfSSL_CertManagerEnableOCSP(ctx->cm, options); else return BAD_FUNC_ARG; } int wolfSSL_CTX_DisableOCSP(WOLFSSL_CTX* ctx) { WOLFSSL_ENTER("wolfSSL_CTX_DisableOCSP"); if (ctx) return wolfSSL_CertManagerDisableOCSP(ctx->cm); else return BAD_FUNC_ARG; } int wolfSSL_CTX_SetOCSP_OverrideURL(WOLFSSL_CTX* ctx, const char* url) { WOLFSSL_ENTER("wolfSSL_SetOCSP_OverrideURL"); if (ctx) return wolfSSL_CertManagerSetOCSPOverrideURL(ctx->cm, url); else return BAD_FUNC_ARG; } int wolfSSL_CTX_SetOCSP_Cb(WOLFSSL_CTX* ctx, CbOCSPIO ioCb, CbOCSPRespFree respFreeCb, void* ioCbCtx) { WOLFSSL_ENTER("wolfSSL_CTX_SetOCSP_Cb"); if (ctx) return wolfSSL_CertManagerSetOCSP_Cb(ctx->cm, ioCb, respFreeCb, ioCbCtx); else return BAD_FUNC_ARG; } #if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) int wolfSSL_CTX_EnableOCSPStapling(WOLFSSL_CTX* ctx) { WOLFSSL_ENTER("wolfSSL_CTX_EnableOCSPStapling"); if (ctx) return wolfSSL_CertManagerEnableOCSPStapling(ctx->cm); else return BAD_FUNC_ARG; } int wolfSSL_CTX_DisableOCSPStapling(WOLFSSL_CTX* ctx) { WOLFSSL_ENTER("wolfSSL_CTX_DisableOCSPStapling"); if (ctx) return wolfSSL_CertManagerDisableOCSPStapling(ctx->cm); else return BAD_FUNC_ARG; } int wolfSSL_CTX_EnableOCSPMustStaple(WOLFSSL_CTX* ctx) { WOLFSSL_ENTER("wolfSSL_CTX_EnableOCSPMustStaple"); if (ctx) return wolfSSL_CertManagerEnableOCSPMustStaple(ctx->cm); else return BAD_FUNC_ARG; } int wolfSSL_CTX_DisableOCSPMustStaple(WOLFSSL_CTX* ctx) { WOLFSSL_ENTER("wolfSSL_CTX_DisableOCSPMustStaple"); if (ctx) return wolfSSL_CertManagerDisableOCSPMustStaple(ctx->cm); else return BAD_FUNC_ARG; } #endif /* HAVE_CERTIFICATE_STATUS_REQUEST || HAVE_CERTIFICATE_STATUS_REQUEST_V2 */ #endif /* HAVE_OCSP */ /* macro to get verify settings for AddCA */ #define GET_VERIFY_SETTING_CTX(ctx) \ ((ctx) && (ctx)->verifyNone ? NO_VERIFY : VERIFY) #define GET_VERIFY_SETTING_SSL(ssl) \ ((ssl)->options.verifyNone ? NO_VERIFY : VERIFY) #ifndef NO_FILESYSTEM /* process a file with name fname into ctx of format and type userChain specifies a user certificate chain to pass during handshake */ int ProcessFile(WOLFSSL_CTX* ctx, const char* fname, int format, int type, WOLFSSL* ssl, int userChain, WOLFSSL_CRL* crl, int verify) { #ifdef WOLFSSL_SMALL_STACK byte staticBuffer[1]; /* force heap usage */ #else byte staticBuffer[FILE_BUFFER_SIZE]; #endif byte* myBuffer = staticBuffer; int dynamic = 0; int ret; long sz = 0; XFILE file; void* heapHint = wolfSSL_CTX_GetHeap(ctx, ssl); #ifndef NO_CODING const char* header = NULL; const char* footer = NULL; #endif (void)crl; (void)heapHint; if (fname == NULL) return WOLFSSL_BAD_FILE; file = XFOPEN(fname, "rb"); if (file == XBADFILE) return WOLFSSL_BAD_FILE; if (XFSEEK(file, 0, XSEEK_END) != 0) { XFCLOSE(file); return WOLFSSL_BAD_FILE; } sz = XFTELL(file); XREWIND(file); if (sz > MAX_WOLFSSL_FILE_SIZE || sz <= 0) { WOLFSSL_MSG("ProcessFile file size error"); XFCLOSE(file); return WOLFSSL_BAD_FILE; } if (sz > (long)sizeof(staticBuffer)) { WOLFSSL_MSG("Getting dynamic buffer"); myBuffer = (byte*)XMALLOC(sz, heapHint, DYNAMIC_TYPE_FILE); if (myBuffer == NULL) { XFCLOSE(file); return WOLFSSL_BAD_FILE; } dynamic = 1; } if ((size_t)XFREAD(myBuffer, 1, sz, file) != (size_t)sz) ret = WOLFSSL_BAD_FILE; else { /* Try to detect type by parsing cert header and footer */ if (type == DETECT_CERT_TYPE) { #ifndef NO_CODING if (wc_PemGetHeaderFooter(CA_TYPE, &header, &footer) == 0 && (XSTRNSTR((char*)myBuffer, header, (int)sz) != NULL)) { type = CA_TYPE; } #ifdef HAVE_CRL else if (wc_PemGetHeaderFooter(CRL_TYPE, &header, &footer) == 0 && (XSTRNSTR((char*)myBuffer, header, (int)sz) != NULL)) { type = CRL_TYPE; } #endif else if (wc_PemGetHeaderFooter(CERT_TYPE, &header, &footer) == 0 && (XSTRNSTR((char*)myBuffer, header, (int)sz) != NULL)) { type = CERT_TYPE; } else #endif { WOLFSSL_MSG("Failed to detect certificate type"); if (dynamic) XFREE(myBuffer, heapHint, DYNAMIC_TYPE_FILE); XFCLOSE(file); return WOLFSSL_BAD_CERTTYPE; } } if ((type == CA_TYPE || type == TRUSTED_PEER_TYPE) && format == WOLFSSL_FILETYPE_PEM) { ret = ProcessChainBuffer(ctx, myBuffer, sz, format, type, ssl, verify); } #ifdef HAVE_CRL else if (type == CRL_TYPE) ret = BufferLoadCRL(crl, myBuffer, sz, format, verify); #endif else ret = ProcessBuffer(ctx, myBuffer, sz, format, type, ssl, NULL, userChain, verify); } XFCLOSE(file); if (dynamic) XFREE(myBuffer, heapHint, DYNAMIC_TYPE_FILE); return ret; } /* loads file then loads each file in path, no c_rehash */ int wolfSSL_CTX_load_verify_locations_ex(WOLFSSL_CTX* ctx, const char* file, const char* path, word32 flags) { int ret = WOLFSSL_SUCCESS; #ifndef NO_WOLFSSL_DIR int fileRet; int successCount = 0; int failCount = 0; #endif int verify; WOLFSSL_MSG("wolfSSL_CTX_load_verify_locations_ex"); if (ctx == NULL || (file == NULL && path == NULL)) { return WOLFSSL_FAILURE; } verify = GET_VERIFY_SETTING_CTX(ctx); if (flags & WOLFSSL_LOAD_FLAG_DATE_ERR_OKAY) verify = VERIFY_SKIP_DATE; if (file) { ret = ProcessFile(ctx, file, WOLFSSL_FILETYPE_PEM, CA_TYPE, NULL, 0, NULL, verify); #ifndef NO_WOLFSSL_DIR if (ret == WOLFSSL_SUCCESS) successCount++; #endif #if defined(WOLFSSL_TRUST_PEER_CERT) && defined(OPENSSL_COMPATIBLE_DEFAULTS) ret = wolfSSL_CTX_trust_peer_cert(ctx, file, WOLFSSL_FILETYPE_PEM); if (ret != WOLFSSL_SUCCESS) { WOLFSSL_MSG("wolfSSL_CTX_trust_peer_cert error"); } #endif } if (ret == WOLFSSL_SUCCESS && path) { #ifndef NO_WOLFSSL_DIR char* name = NULL; #ifdef WOLFSSL_SMALL_STACK ReadDirCtx* readCtx; readCtx = (ReadDirCtx*)XMALLOC(sizeof(ReadDirCtx), ctx->heap, DYNAMIC_TYPE_DIRCTX); if (readCtx == NULL) return MEMORY_E; #else ReadDirCtx readCtx[1]; #endif /* try to load each regular file in path */ fileRet = wc_ReadDirFirst(readCtx, path, &name); while (fileRet == 0 && name) { WOLFSSL_MSG(name); /* log file name */ ret = ProcessFile(ctx, name, WOLFSSL_FILETYPE_PEM, CA_TYPE, NULL, 0, NULL, verify); if (ret != WOLFSSL_SUCCESS) { /* handle flags for ignoring errors, skipping expired certs or by PEM certificate header error */ if ( (flags & WOLFSSL_LOAD_FLAG_IGNORE_ERR) || ((flags & WOLFSSL_LOAD_FLAG_PEM_CA_ONLY) && (ret == ASN_NO_PEM_HEADER))) { /* Do not fail here if a certificate fails to load, continue to next file */ unsigned long err; CLEAR_ASN_NO_PEM_HEADER_ERROR(err); #if defined(WOLFSSL_QT) ret = WOLFSSL_SUCCESS; #endif } else { WOLFSSL_ERROR(ret); WOLFSSL_MSG("Load CA file failed, continuing"); failCount++; } } else { #if defined(WOLFSSL_TRUST_PEER_CERT) && defined(OPENSSL_COMPATIBLE_DEFAULTS) ret = wolfSSL_CTX_trust_peer_cert(ctx, file, WOLFSSL_FILETYPE_PEM); if (ret != WOLFSSL_SUCCESS) { WOLFSSL_MSG("wolfSSL_CTX_trust_peer_cert error. Ignoring" "this error."); } #endif successCount++; } fileRet = wc_ReadDirNext(readCtx, path, &name); } wc_ReadDirClose(readCtx); /* pass directory read failure to response code */ if (fileRet != WC_READDIR_NOFILE) { ret = fileRet; #if defined(WOLFSSL_QT) if (ret == BAD_PATH_ERROR && flags & WOLFSSL_LOAD_FLAG_IGNORE_BAD_PATH_ERR) { /* QSslSocket always loads certs in system folder * when it is initialized. * Compliant with OpenSSL when flag sets. */ ret = WOLFSSL_SUCCESS; } else { /* qssl socket wants to know errors. */ WOLFSSL_ERROR(ret); } #endif } /* report failure if no files were loaded or there were failures */ else if (successCount == 0 || failCount > 0) { /* use existing error code if exists */ #if defined(WOLFSSL_QT) /* compliant with OpenSSL when flag sets*/ if (!(flags & WOLFSSL_LOAD_FLAG_IGNORE_ZEROFILE)) #endif { ret = WOLFSSL_FAILURE; } } else { ret = WOLFSSL_SUCCESS; } #ifdef WOLFSSL_SMALL_STACK XFREE(readCtx, ctx->heap, DYNAMIC_TYPE_DIRCTX); #endif #else ret = NOT_COMPILED_IN; (void)flags; #endif } return ret; } WOLFSSL_ABI int wolfSSL_CTX_load_verify_locations(WOLFSSL_CTX* ctx, const char* file, const char* path) { int ret = wolfSSL_CTX_load_verify_locations_ex(ctx, file, path, WOLFSSL_LOAD_VERIFY_DEFAULT_FLAGS); return WS_RETURN_CODE(ret,WOLFSSL_FAILURE); } #ifdef WOLFSSL_TRUST_PEER_CERT /* Used to specify a peer cert to match when connecting ctx : the ctx structure to load in peer cert file: the string name of cert file type: type of format such as PEM/DER */ int wolfSSL_CTX_trust_peer_cert(WOLFSSL_CTX* ctx, const char* file, int type) { WOLFSSL_ENTER("wolfSSL_CTX_trust_peer_cert"); if (ctx == NULL || file == NULL) { return WOLFSSL_FAILURE; } return ProcessFile(ctx, file, type, TRUSTED_PEER_TYPE, NULL, 0, NULL, GET_VERIFY_SETTING_CTX(ctx)); } int wolfSSL_trust_peer_cert(WOLFSSL* ssl, const char* file, int type) { WOLFSSL_ENTER("wolfSSL_trust_peer_cert"); if (ssl == NULL || file == NULL) { return WOLFSSL_FAILURE; } return ProcessFile(NULL, file, type, TRUSTED_PEER_TYPE, ssl, 0, NULL, GET_VERIFY_SETTING_SSL(ssl)); } #endif /* WOLFSSL_TRUST_PEER_CERT */ #if !defined(NO_WOLFSSL_CLIENT) || !defined(WOLFSSL_NO_CLIENT_AUTH) /* Verify the certificate, WOLFSSL_SUCCESS for ok, < 0 for error */ int wolfSSL_CertManagerVerify(WOLFSSL_CERT_MANAGER* cm, const char* fname, int format) { int ret = WOLFSSL_FATAL_ERROR; #ifdef WOLFSSL_SMALL_STACK byte staticBuffer[1]; /* force heap usage */ #else byte staticBuffer[FILE_BUFFER_SIZE]; #endif byte* myBuffer = staticBuffer; int dynamic = 0; long sz = 0; XFILE file = XFOPEN(fname, "rb"); WOLFSSL_ENTER("wolfSSL_CertManagerVerify"); if (file == XBADFILE) return WOLFSSL_BAD_FILE; if(XFSEEK(file, 0, XSEEK_END) != 0) { XFCLOSE(file); return WOLFSSL_BAD_FILE; } sz = XFTELL(file); XREWIND(file); if (sz > MAX_WOLFSSL_FILE_SIZE || sz <= 0) { WOLFSSL_MSG("CertManagerVerify file size error"); XFCLOSE(file); return WOLFSSL_BAD_FILE; } if (sz > (long)sizeof(staticBuffer)) { WOLFSSL_MSG("Getting dynamic buffer"); myBuffer = (byte*) XMALLOC(sz, cm->heap, DYNAMIC_TYPE_FILE); if (myBuffer == NULL) { XFCLOSE(file); return WOLFSSL_BAD_FILE; } dynamic = 1; } if ((size_t)XFREAD(myBuffer, 1, sz, file) != (size_t)sz) ret = WOLFSSL_BAD_FILE; else ret = wolfSSL_CertManagerVerifyBuffer(cm, myBuffer, sz, format); XFCLOSE(file); if (dynamic) XFREE(myBuffer, cm->heap, DYNAMIC_TYPE_FILE); return ret; } #endif /* like load verify locations, 1 for success, < 0 for error */ int wolfSSL_CertManagerLoadCA(WOLFSSL_CERT_MANAGER* cm, const char* file, const char* path) { int ret = WOLFSSL_FATAL_ERROR; WOLFSSL_CTX* tmp; WOLFSSL_ENTER("wolfSSL_CertManagerLoadCA"); if (cm == NULL) { WOLFSSL_MSG("No CertManager error"); return ret; } tmp = wolfSSL_CTX_new(cm_pick_method()); if (tmp == NULL) { WOLFSSL_MSG("CTX new failed"); return ret; } /* for tmp use */ wolfSSL_CertManagerFree(tmp->cm); tmp->cm = cm; ret = wolfSSL_CTX_load_verify_locations(tmp, file, path); /* don't lose our good one */ tmp->cm = NULL; wolfSSL_CTX_free(tmp); return ret; } #endif /* NO_FILESYSTEM */ #ifdef HAVE_CRL /* check CRL if enabled, WOLFSSL_SUCCESS */ int wolfSSL_CertManagerCheckCRL(WOLFSSL_CERT_MANAGER* cm, byte* der, int sz) { int ret = 0; #ifdef WOLFSSL_SMALL_STACK DecodedCert* cert = NULL; #else DecodedCert cert[1]; #endif WOLFSSL_ENTER("wolfSSL_CertManagerCheckCRL"); if (cm == NULL) return BAD_FUNC_ARG; if (cm->crlEnabled == 0) return WOLFSSL_SUCCESS; #ifdef WOLFSSL_SMALL_STACK cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, DYNAMIC_TYPE_DCERT); if (cert == NULL) return MEMORY_E; #endif InitDecodedCert(cert, der, sz, NULL); if ((ret = ParseCertRelative(cert, CERT_TYPE, VERIFY_CRL, cm)) != 0) { WOLFSSL_MSG("ParseCert failed"); } else if ((ret = CheckCertCRL(cm->crl, cert)) != 0) { WOLFSSL_MSG("CheckCertCRL failed"); } FreeDecodedCert(cert); #ifdef WOLFSSL_SMALL_STACK XFREE(cert, NULL, DYNAMIC_TYPE_DCERT); #endif return ret == 0 ? WOLFSSL_SUCCESS : ret; } int wolfSSL_CertManagerSetCRL_Cb(WOLFSSL_CERT_MANAGER* cm, CbMissingCRL cb) { WOLFSSL_ENTER("wolfSSL_CertManagerSetCRL_Cb"); if (cm == NULL) return BAD_FUNC_ARG; cm->cbMissingCRL = cb; return WOLFSSL_SUCCESS; } #ifdef HAVE_CRL_IO int wolfSSL_CertManagerSetCRL_IOCb(WOLFSSL_CERT_MANAGER* cm, CbCrlIO cb) { if (cm == NULL) return BAD_FUNC_ARG; cm->crl->crlIOCb = cb; return WOLFSSL_SUCCESS; } #endif #ifndef NO_FILESYSTEM int wolfSSL_CertManagerLoadCRL(WOLFSSL_CERT_MANAGER* cm, const char* path, int type, int monitor) { WOLFSSL_ENTER("wolfSSL_CertManagerLoadCRL"); if (cm == NULL) return BAD_FUNC_ARG; if (cm->crl == NULL) { if (wolfSSL_CertManagerEnableCRL(cm, 0) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("Enable CRL failed"); return WOLFSSL_FATAL_ERROR; } } return LoadCRL(cm->crl, path, type, monitor); } int wolfSSL_CertManagerLoadCRLFile(WOLFSSL_CERT_MANAGER* cm, const char* file, int type) { WOLFSSL_ENTER("wolfSSL_CertManagerLoadCRLFile"); if (cm == NULL || file == NULL) return BAD_FUNC_ARG; if (cm->crl == NULL) { if (wolfSSL_CertManagerEnableCRL(cm, 0) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("Enable CRL failed"); return WOLFSSL_FATAL_ERROR; } } return ProcessFile(NULL, file, type, CRL_TYPE, NULL, 0, cm->crl, VERIFY); } #endif int wolfSSL_EnableCRL(WOLFSSL* ssl, int options) { WOLFSSL_ENTER("wolfSSL_EnableCRL"); if (ssl) return wolfSSL_CertManagerEnableCRL(SSL_CM(ssl), options); else return BAD_FUNC_ARG; } int wolfSSL_DisableCRL(WOLFSSL* ssl) { WOLFSSL_ENTER("wolfSSL_DisableCRL"); if (ssl) return wolfSSL_CertManagerDisableCRL(SSL_CM(ssl)); else return BAD_FUNC_ARG; } #ifndef NO_FILESYSTEM int wolfSSL_LoadCRL(WOLFSSL* ssl, const char* path, int type, int monitor) { WOLFSSL_ENTER("wolfSSL_LoadCRL"); if (ssl) return wolfSSL_CertManagerLoadCRL(SSL_CM(ssl), path, type, monitor); else return BAD_FUNC_ARG; } int wolfSSL_LoadCRLFile(WOLFSSL* ssl, const char* file, int type) { WOLFSSL_ENTER("wolfSSL_LoadCRL"); if (ssl) return wolfSSL_CertManagerLoadCRLFile(SSL_CM(ssl), file, type); else return BAD_FUNC_ARG; } #endif int wolfSSL_SetCRL_Cb(WOLFSSL* ssl, CbMissingCRL cb) { WOLFSSL_ENTER("wolfSSL_SetCRL_Cb"); if (ssl) return wolfSSL_CertManagerSetCRL_Cb(SSL_CM(ssl), cb); else return BAD_FUNC_ARG; } #ifdef HAVE_CRL_IO int wolfSSL_SetCRL_IOCb(WOLFSSL* ssl, CbCrlIO cb) { WOLFSSL_ENTER("wolfSSL_SetCRL_Cb"); if (ssl) return wolfSSL_CertManagerSetCRL_IOCb(SSL_CM(ssl), cb); else return BAD_FUNC_ARG; } #endif int wolfSSL_CTX_EnableCRL(WOLFSSL_CTX* ctx, int options) { WOLFSSL_ENTER("wolfSSL_CTX_EnableCRL"); if (ctx) return wolfSSL_CertManagerEnableCRL(ctx->cm, options); else return BAD_FUNC_ARG; } int wolfSSL_CTX_DisableCRL(WOLFSSL_CTX* ctx) { WOLFSSL_ENTER("wolfSSL_CTX_DisableCRL"); if (ctx) return wolfSSL_CertManagerDisableCRL(ctx->cm); else return BAD_FUNC_ARG; } #ifndef NO_FILESYSTEM int wolfSSL_CTX_LoadCRL(WOLFSSL_CTX* ctx, const char* path, int type, int monitor) { WOLFSSL_ENTER("wolfSSL_CTX_LoadCRL"); if (ctx) return wolfSSL_CertManagerLoadCRL(ctx->cm, path, type, monitor); else return BAD_FUNC_ARG; } int wolfSSL_CTX_LoadCRLFile(WOLFSSL_CTX* ctx, const char* file, int type) { WOLFSSL_ENTER("wolfSSL_CTX_LoadCRL"); if (ctx) return wolfSSL_CertManagerLoadCRLFile(ctx->cm, file, type); else return BAD_FUNC_ARG; } #endif int wolfSSL_CTX_SetCRL_Cb(WOLFSSL_CTX* ctx, CbMissingCRL cb) { WOLFSSL_ENTER("wolfSSL_CTX_SetCRL_Cb"); if (ctx) return wolfSSL_CertManagerSetCRL_Cb(ctx->cm, cb); else return BAD_FUNC_ARG; } #ifdef HAVE_CRL_IO int wolfSSL_CTX_SetCRL_IOCb(WOLFSSL_CTX* ctx, CbCrlIO cb) { WOLFSSL_ENTER("wolfSSL_CTX_SetCRL_IOCb"); if (ctx) return wolfSSL_CertManagerSetCRL_IOCb(ctx->cm, cb); else return BAD_FUNC_ARG; } #endif #endif /* HAVE_CRL */ #ifndef NO_FILESYSTEM #ifdef WOLFSSL_DER_LOAD /* Add format parameter to allow DER load of CA files */ int wolfSSL_CTX_der_load_verify_locations(WOLFSSL_CTX* ctx, const char* file, int format) { WOLFSSL_ENTER("wolfSSL_CTX_der_load_verify_locations"); if (ctx == NULL || file == NULL) return WOLFSSL_FAILURE; if (ProcessFile(ctx, file, format, CA_TYPE, NULL, 0, NULL, GET_VERIFY_SETTING_CTX(ctx)) == WOLFSSL_SUCCESS) { return WOLFSSL_SUCCESS; } return WOLFSSL_FAILURE; } #endif /* WOLFSSL_DER_LOAD */ WOLFSSL_ABI int wolfSSL_CTX_use_certificate_file(WOLFSSL_CTX* ctx, const char* file, int format) { WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_file"); if (ProcessFile(ctx, file, format, CERT_TYPE, NULL, 0, NULL, GET_VERIFY_SETTING_CTX(ctx)) == WOLFSSL_SUCCESS) { return WOLFSSL_SUCCESS; } return WOLFSSL_FAILURE; } WOLFSSL_ABI int wolfSSL_CTX_use_PrivateKey_file(WOLFSSL_CTX* ctx, const char* file, int format) { WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey_file"); if (ProcessFile(ctx, file, format, PRIVATEKEY_TYPE, NULL, 0, NULL, GET_VERIFY_SETTING_CTX(ctx)) == WOLFSSL_SUCCESS) { return WOLFSSL_SUCCESS; } return WOLFSSL_FAILURE; } #endif /* NO_FILESYSTEM */ /* Sets the max chain depth when verifying a certificate chain. Default depth * is set to MAX_CHAIN_DEPTH. * * ctx WOLFSSL_CTX structure to set depth in * depth max depth */ void wolfSSL_CTX_set_verify_depth(WOLFSSL_CTX *ctx, int depth) { WOLFSSL_ENTER("wolfSSL_CTX_set_verify_depth"); if (ctx == NULL || depth < 0 || depth > MAX_CHAIN_DEPTH) { WOLFSSL_MSG("Bad depth argument, too large or less than 0"); return; } ctx->verifyDepth = (byte)depth; } /* get cert chaining depth using ssl struct */ long wolfSSL_get_verify_depth(WOLFSSL* ssl) { if(ssl == NULL) { return BAD_FUNC_ARG; } #ifndef OPENSSL_EXTRA return MAX_CHAIN_DEPTH; #else return ssl->options.verifyDepth; #endif } /* get cert chaining depth using ctx struct */ long wolfSSL_CTX_get_verify_depth(WOLFSSL_CTX* ctx) { if (ctx == NULL) { return BAD_FUNC_ARG; } #ifndef OPENSSL_EXTRA return MAX_CHAIN_DEPTH; #else return ctx->verifyDepth; #endif } #ifndef NO_FILESYSTEM WOLFSSL_ABI int wolfSSL_CTX_use_certificate_chain_file(WOLFSSL_CTX* ctx, const char* file) { /* process up to MAX_CHAIN_DEPTH plus subject cert */ WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_chain_file"); if (ProcessFile(ctx, file, WOLFSSL_FILETYPE_PEM, CERT_TYPE, NULL, 1, NULL, GET_VERIFY_SETTING_CTX(ctx)) == WOLFSSL_SUCCESS) { return WOLFSSL_SUCCESS; } return WOLFSSL_FAILURE; } int wolfSSL_CTX_use_certificate_chain_file_format(WOLFSSL_CTX* ctx, const char* file, int format) { /* process up to MAX_CHAIN_DEPTH plus subject cert */ WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_chain_file_format"); if (ProcessFile(ctx, file, format, CERT_TYPE, NULL, 1, NULL, GET_VERIFY_SETTING_CTX(ctx)) == WOLFSSL_SUCCESS) { return WOLFSSL_SUCCESS; } return WOLFSSL_FAILURE; } #ifndef NO_DH /* server Diffie-Hellman parameters */ static int wolfSSL_SetTmpDH_file_wrapper(WOLFSSL_CTX* ctx, WOLFSSL* ssl, const char* fname, int format) { #ifdef WOLFSSL_SMALL_STACK byte staticBuffer[1]; /* force heap usage */ #else byte staticBuffer[FILE_BUFFER_SIZE]; #endif byte* myBuffer = staticBuffer; int dynamic = 0; int ret; long sz = 0; XFILE file; if (ctx == NULL || fname == NULL) return BAD_FUNC_ARG; file = XFOPEN(fname, "rb"); if (file == XBADFILE) return WOLFSSL_BAD_FILE; if(XFSEEK(file, 0, XSEEK_END) != 0) { XFCLOSE(file); return WOLFSSL_BAD_FILE; } sz = XFTELL(file); XREWIND(file); if (sz > MAX_WOLFSSL_FILE_SIZE || sz <= 0) { WOLFSSL_MSG("SetTmpDH file size error"); XFCLOSE(file); return WOLFSSL_BAD_FILE; } if (sz > (long)sizeof(staticBuffer)) { WOLFSSL_MSG("Getting dynamic buffer"); myBuffer = (byte*) XMALLOC(sz, ctx->heap, DYNAMIC_TYPE_FILE); if (myBuffer == NULL) { XFCLOSE(file); return WOLFSSL_BAD_FILE; } dynamic = 1; } if ((size_t)XFREAD(myBuffer, 1, sz, file) != (size_t)sz) ret = WOLFSSL_BAD_FILE; else { if (ssl) ret = wolfSSL_SetTmpDH_buffer(ssl, myBuffer, sz, format); else ret = wolfSSL_CTX_SetTmpDH_buffer(ctx, myBuffer, sz, format); } XFCLOSE(file); if (dynamic) XFREE(myBuffer, ctx->heap, DYNAMIC_TYPE_FILE); return ret; } /* server Diffie-Hellman parameters */ int wolfSSL_SetTmpDH_file(WOLFSSL* ssl, const char* fname, int format) { if (ssl == NULL) return BAD_FUNC_ARG; return wolfSSL_SetTmpDH_file_wrapper(ssl->ctx, ssl, fname, format); } /* server Diffie-Hellman parameters */ int wolfSSL_CTX_SetTmpDH_file(WOLFSSL_CTX* ctx, const char* fname, int format) { return wolfSSL_SetTmpDH_file_wrapper(ctx, NULL, fname, format); } #endif /* NO_DH */ #endif /* NO_FILESYSTEM */ #ifndef NO_CHECK_PRIVATE_KEY /* Check private against public in certificate for match * * Returns WOLFSSL_SUCCESS on good private key * WOLFSSL_FAILURE if mismatched */ static int check_cert_key(DerBuffer* cert, DerBuffer* key, void* heap, int devId, int isKeyLabel, int isKeyId) { #ifdef WOLFSSL_SMALL_STACK DecodedCert* der = NULL; #else DecodedCert der[1]; #endif word32 size; byte* buff; int ret = WOLFSSL_FAILURE; WOLFSSL_ENTER("check_cert_key"); if (cert == NULL || key == NULL) { return WOLFSSL_FAILURE; } #ifdef WOLFSSL_SMALL_STACK der = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, DYNAMIC_TYPE_DCERT); if (der == NULL) return MEMORY_E; #endif size = cert->length; buff = cert->buffer; InitDecodedCert(der, buff, size, heap); if (ParseCertRelative(der, CERT_TYPE, NO_VERIFY, NULL) != 0) { FreeDecodedCert(der); #ifdef WOLFSSL_SMALL_STACK XFREE(der, NULL, DYNAMIC_TYPE_DCERT); #endif return WOLFSSL_FAILURE; } size = key->length; buff = key->buffer; #ifdef WOLF_PRIVATE_KEY_ID if (devId != INVALID_DEVID) { int type = 0; void *pkey = NULL; #ifndef NO_RSA if (der->keyOID == RSAk) { type = DYNAMIC_TYPE_RSA; } #endif #ifdef HAVE_ECC if (der->keyOID == ECDSAk) { type = DYNAMIC_TYPE_ECC; } #endif ret = CreateDevPrivateKey(&pkey, buff, size, type, isKeyLabel, isKeyId, heap, devId); #ifdef WOLF_CRYPTO_CB if (ret == 0) { #ifndef NO_RSA if (der->keyOID == RSAk) { ret = wc_CryptoCb_RsaCheckPrivKey((RsaKey*)pkey, der->publicKey, der->pubKeySize); } #endif #ifdef HAVE_ECC if (der->keyOID == ECDSAk) { ret = wc_CryptoCb_EccCheckPrivKey((ecc_key*)pkey, der->publicKey, der->pubKeySize); } #endif } #else /* devId was set, don't check, for now */ /* TODO: Add callback for private key check? */ #endif if (pkey != NULL) { #ifndef NO_RSA if (der->keyOID == RSAk) { wc_FreeRsaKey((RsaKey*)pkey); } #endif #ifdef HAVE_ECC if (der->keyOID == ECDSAk) { wc_ecc_free((ecc_key*)pkey); } #endif XFREE(pkey, heap, type); } if (ret != CRYPTOCB_UNAVAILABLE) { ret = (ret == 0) ? WOLFSSL_SUCCESS: WOLFSSL_FAILURE; } } else { /* fall through if unavailable */ ret = CRYPTOCB_UNAVAILABLE; } if (ret == CRYPTOCB_UNAVAILABLE) #endif /* WOLF_PRIVATE_KEY_ID */ { ret = wc_CheckPrivateKeyCert(buff, size, der); ret = (ret == 1) ? WOLFSSL_SUCCESS: WOLFSSL_FAILURE; } FreeDecodedCert(der); #ifdef WOLFSSL_SMALL_STACK XFREE(der, NULL, DYNAMIC_TYPE_DCERT); #endif (void)devId; (void)isKeyLabel; (void)isKeyId; return ret; } /* Check private against public in certificate for match * * ctx WOLFSSL_CTX structure to check private key in * * Returns WOLFSSL_SUCCESS on good private key * WOLFSSL_FAILURE if mismatched. */ int wolfSSL_CTX_check_private_key(const WOLFSSL_CTX* ctx) { if (ctx == NULL) { return WOLFSSL_FAILURE; } return check_cert_key(ctx->certificate, ctx->privateKey, ctx->heap, ctx->privateKeyDevId, ctx->privateKeyLabel, ctx->privateKeyId); } #endif /* !NO_CHECK_PRIVATE_KEY */ #ifdef OPENSSL_ALL /** * Return the private key of the WOLFSSL_CTX struct * @return WOLFSSL_EVP_PKEY* The caller doesn *NOT*` free the returned object. */ WOLFSSL_EVP_PKEY* wolfSSL_CTX_get0_privatekey(const WOLFSSL_CTX* ctx) { const unsigned char *key; int type; WOLFSSL_ENTER("wolfSSL_CTX_get0_privatekey"); if (ctx == NULL || ctx->privateKey == NULL || ctx->privateKey->buffer == NULL) { WOLFSSL_MSG("Bad parameter or key not set"); return NULL; } switch (ctx->privateKeyType) { #ifndef NO_RSA case rsa_sa_algo: type = EVP_PKEY_RSA; break; #endif #ifdef HAVE_ECC case ecc_dsa_sa_algo: type = EVP_PKEY_EC; break; #endif default: /* Other key types not supported either as ssl private keys * or in the EVP layer */ WOLFSSL_MSG("Unsupported key type"); return NULL; } key = ctx->privateKey->buffer; if (ctx->privateKeyPKey != NULL) return ctx->privateKeyPKey; else return wolfSSL_d2i_PrivateKey(type, (WOLFSSL_EVP_PKEY**)&ctx->privateKeyPKey, &key, (long)ctx->privateKey->length); } #endif #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) static WOLFSSL_EVP_PKEY* d2iGenericKey(WOLFSSL_EVP_PKEY** out, const unsigned char** in, long inSz, int priv) { WOLFSSL_EVP_PKEY* pkey = NULL; const unsigned char* mem; long memSz = inSz; WOLFSSL_ENTER("d2iGenericKey"); if (in == NULL || *in == NULL || inSz < 0) { WOLFSSL_MSG("Bad argument"); return NULL; } mem = *in; #if !defined(NO_RSA) { word32 keyIdx = 0; int isRsaKey; #ifdef WOLFSSL_SMALL_STACK RsaKey *rsa = (RsaKey*)XMALLOC(sizeof(RsaKey), NULL, DYNAMIC_TYPE_RSA); if (rsa == NULL) return NULL; #else RsaKey rsa[1]; #endif XMEMSET(rsa, 0, sizeof(RsaKey)); /* test if RSA key */ if (priv) isRsaKey = wc_InitRsaKey(rsa, NULL) == 0 && wc_RsaPrivateKeyDecode(mem, &keyIdx, rsa, (word32)memSz) == 0; else isRsaKey = wc_InitRsaKey(rsa, NULL) == 0 && wc_RsaPublicKeyDecode(mem, &keyIdx, rsa, (word32)memSz) == 0; wc_FreeRsaKey(rsa); #ifdef WOLFSSL_SMALL_STACK XFREE(rsa, NULL, DYNAMIC_TYPE_RSA); #endif if (isRsaKey) { pkey = wolfSSL_EVP_PKEY_new(); if (pkey != NULL) { pkey->pkey_sz = keyIdx; pkey->pkey.ptr = (char*)XMALLOC(memSz, NULL, priv ? DYNAMIC_TYPE_PRIVATE_KEY : DYNAMIC_TYPE_PUBLIC_KEY); if (pkey->pkey.ptr == NULL) { wolfSSL_EVP_PKEY_free(pkey); return NULL; } XMEMCPY(pkey->pkey.ptr, mem, keyIdx); pkey->type = EVP_PKEY_RSA; if (out != NULL) { *out = pkey; } pkey->ownRsa = 1; pkey->rsa = wolfSSL_RSA_new(); if (pkey->rsa == NULL) { wolfSSL_EVP_PKEY_free(pkey); return NULL; } if (wolfSSL_RSA_LoadDer_ex(pkey->rsa, (const unsigned char*)pkey->pkey.ptr, pkey->pkey_sz, priv ? WOLFSSL_RSA_LOAD_PRIVATE : WOLFSSL_RSA_LOAD_PUBLIC) != 1) { wolfSSL_EVP_PKEY_free(pkey); return NULL; } return pkey; } else { WOLFSSL_MSG("RSA wolfSSL_EVP_PKEY_new error"); } } } #endif /* NO_RSA */ #if defined(HAVE_ECC) && defined(OPENSSL_EXTRA) { word32 keyIdx = 0; int isEccKey; #ifdef WOLFSSL_SMALL_STACK ecc_key *ecc = (ecc_key*)XMALLOC(sizeof(ecc_key), NULL, DYNAMIC_TYPE_ECC); if (ecc == NULL) return NULL; #else ecc_key ecc[1]; #endif XMEMSET(ecc, 0, sizeof(ecc_key)); if (priv) isEccKey = wc_ecc_init(ecc) == 0 && wc_EccPrivateKeyDecode(mem, &keyIdx, ecc, (word32)memSz) == 0; else isEccKey = wc_ecc_init(ecc) == 0 && wc_EccPublicKeyDecode(mem, &keyIdx, ecc, (word32)memSz) == 0; wc_ecc_free(ecc); #ifdef WOLFSSL_SMALL_STACK XFREE(ecc, NULL, DYNAMIC_TYPE_ECC); #endif if (isEccKey) { pkey = wolfSSL_EVP_PKEY_new(); if (pkey != NULL) { pkey->pkey_sz = keyIdx; pkey->pkey.ptr = (char*)XMALLOC(keyIdx, NULL, priv ? DYNAMIC_TYPE_PRIVATE_KEY : DYNAMIC_TYPE_PUBLIC_KEY); if (pkey->pkey.ptr == NULL) { wolfSSL_EVP_PKEY_free(pkey); return NULL; } XMEMCPY(pkey->pkey.ptr, mem, keyIdx); pkey->type = EVP_PKEY_EC; if (out != NULL) { *out = pkey; } pkey->ownEcc = 1; pkey->ecc = wolfSSL_EC_KEY_new(); if (pkey->ecc == NULL) { wolfSSL_EVP_PKEY_free(pkey); return NULL; } if (wolfSSL_EC_KEY_LoadDer_ex(pkey->ecc, (const unsigned char*)pkey->pkey.ptr, pkey->pkey_sz, priv ? WOLFSSL_RSA_LOAD_PRIVATE : WOLFSSL_RSA_LOAD_PUBLIC) != 1) { wolfSSL_EVP_PKEY_free(pkey); return NULL; } return pkey; } else { WOLFSSL_MSG("ECC wolfSSL_EVP_PKEY_new error"); } } } #endif /* HAVE_ECC && OPENSSL_EXTRA */ #if !defined(NO_DSA) { word32 keyIdx = 0; int isDsaKey; #ifdef WOLFSSL_SMALL_STACK DsaKey *dsa = (DsaKey*)XMALLOC(sizeof(DsaKey), NULL, DYNAMIC_TYPE_DSA); if (dsa == NULL) return NULL; #else DsaKey dsa[1]; #endif XMEMSET(dsa, 0, sizeof(DsaKey)); if (priv) isDsaKey = wc_InitDsaKey(dsa) == 0 && wc_DsaPrivateKeyDecode(mem, &keyIdx, dsa, (word32)memSz) == 0; else isDsaKey = wc_InitDsaKey(dsa) == 0 && wc_DsaPublicKeyDecode(mem, &keyIdx, dsa, (word32)memSz) == 0; wc_FreeDsaKey(dsa); #ifdef WOLFSSL_SMALL_STACK XFREE(dsa, NULL, DYNAMIC_TYPE_DSA); #endif /* test if DSA key */ if (isDsaKey) { pkey = wolfSSL_EVP_PKEY_new(); if (pkey != NULL) { pkey->pkey_sz = keyIdx; pkey->pkey.ptr = (char*)XMALLOC(memSz, NULL, priv ? DYNAMIC_TYPE_PRIVATE_KEY : DYNAMIC_TYPE_PUBLIC_KEY); if (pkey->pkey.ptr == NULL) { wolfSSL_EVP_PKEY_free(pkey); return NULL; } XMEMCPY(pkey->pkey.ptr, mem, keyIdx); pkey->type = EVP_PKEY_DSA; if (out != NULL) { *out = pkey; } pkey->ownDsa = 1; pkey->dsa = wolfSSL_DSA_new(); if (pkey->dsa == NULL) { wolfSSL_EVP_PKEY_free(pkey); return NULL; } if (wolfSSL_DSA_LoadDer_ex(pkey->dsa, (const unsigned char*)pkey->pkey.ptr, pkey->pkey_sz, priv ? WOLFSSL_RSA_LOAD_PRIVATE : WOLFSSL_RSA_LOAD_PUBLIC) != 1) { wolfSSL_EVP_PKEY_free(pkey); return NULL; } return pkey; } else { WOLFSSL_MSG("DSA wolfSSL_EVP_PKEY_new error"); } } } #endif /* NO_DSA */ #if !defined(NO_DH) && (defined(WOLFSSL_QT) || defined(OPENSSL_ALL)) #if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \ (HAVE_FIPS_VERSION > 2)) { int isDhKey; word32 keyIdx = 0; #ifdef WOLFSSL_SMALL_STACK DhKey *dh = (DhKey*)XMALLOC(sizeof(DhKey), NULL, DYNAMIC_TYPE_DH); if (dh == NULL) return NULL; #else DhKey dh[1]; #endif XMEMSET(dh, 0, sizeof(DhKey)); isDhKey = wc_InitDhKey(dh) == 0 && wc_DhKeyDecode(mem, &keyIdx, dh, (word32)memSz) == 0; wc_FreeDhKey(dh); #ifdef WOLFSSL_SMALL_STACK XFREE(dh, NULL, DYNAMIC_TYPE_DH); #endif /* test if DH key */ if (isDhKey) { pkey = wolfSSL_EVP_PKEY_new(); if (pkey != NULL) { pkey->pkey_sz = (int)memSz; pkey->pkey.ptr = (char*)XMALLOC(memSz, NULL, priv ? DYNAMIC_TYPE_PRIVATE_KEY : DYNAMIC_TYPE_PUBLIC_KEY); if (pkey->pkey.ptr == NULL) { wolfSSL_EVP_PKEY_free(pkey); return NULL; } XMEMCPY(pkey->pkey.ptr, mem, memSz); pkey->type = EVP_PKEY_DH; if (out != NULL) { *out = pkey; } pkey->ownDh = 1; pkey->dh = wolfSSL_DH_new(); if (pkey->dh == NULL) { wolfSSL_EVP_PKEY_free(pkey); return NULL; } if (wolfSSL_DH_LoadDer(pkey->dh, (const unsigned char*)pkey->pkey.ptr, pkey->pkey_sz) != WOLFSSL_SUCCESS) { wolfSSL_EVP_PKEY_free(pkey); return NULL; } return pkey; } else { WOLFSSL_MSG("DH wolfSSL_EVP_PKEY_new error"); } } } #endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */ #endif /* !NO_DH && (WOLFSSL_QT || OPENSSL_ALL) */ #if !defined(NO_DH) && defined(OPENSSL_EXTRA) && defined(WOLFSSL_DH_EXTRA) #if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \ (HAVE_FIPS_VERSION > 2)) { word32 keyIdx = 0; DhKey* key = NULL; int ret; int elements; #ifdef WOLFSSL_SMALL_STACK DhKey* dh = (DhKey*)XMALLOC(sizeof(DhKey), NULL, DYNAMIC_TYPE_DH); if (dh == NULL) return NULL; #else DhKey dh[1]; #endif XMEMSET(dh, 0, sizeof(DhKey)); /* test if DH-public key */ if (wc_InitDhKey(dh) != 0) return NULL; ret = wc_DhKeyDecode(mem, &keyIdx, dh, (word32)memSz); wc_FreeDhKey(dh); #ifdef WOLFSSL_SMALL_STACK XFREE(dh, NULL, DYNAMIC_TYPE_DH); #endif if (ret == 0) { pkey = wolfSSL_EVP_PKEY_new(); if (pkey != NULL) { pkey->type = EVP_PKEY_DH; pkey->pkey_sz = (int)memSz; pkey->pkey.ptr = (char*)XMALLOC(memSz, NULL, priv ? DYNAMIC_TYPE_PRIVATE_KEY : DYNAMIC_TYPE_PUBLIC_KEY); if (pkey->pkey.ptr == NULL) { wolfSSL_EVP_PKEY_free(pkey); return NULL; } XMEMCPY(pkey->pkey.ptr, mem, memSz); if (out != NULL) { *out = pkey; } pkey->ownDh = 1; pkey->dh = wolfSSL_DH_new(); if (pkey->dh == NULL) { wolfSSL_EVP_PKEY_free(pkey); return NULL; } key = (DhKey*)pkey->dh->internal; keyIdx = 0; if (wc_DhKeyDecode(mem, &keyIdx, key, (word32)memSz) == 0) { elements = ELEMENT_P | ELEMENT_G | ELEMENT_Q | ELEMENT_PUB; if (priv) elements |= ELEMENT_PRV; if(SetDhExternal_ex(pkey->dh, elements) == WOLFSSL_SUCCESS ) { return pkey; } } else { wolfSSL_EVP_PKEY_free(pkey); return NULL; } } } } #endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */ #endif /* !NO_DH && OPENSSL_EXTRA && WOLFSSL_DH_EXTRA */ #ifdef HAVE_PQC { int isFalcon = 0; #ifdef WOLFSSL_SMALL_STACK falcon_key *falcon = (falcon_key *)MALLOC(sizeof(falcon_key), NULL, DYNAMIC_TYPE_FALCON); if (falcon == NULL) { return NULL; } #else falcon_key falcon[1]; #endif if (wc_falcon_init(falcon) == 0) { /* test if Falcon key */ if (priv) { /* Try level 1 */ isFalcon = wc_falcon_set_level(falcon, 1) == 0 && wc_falcon_import_private_only(mem, (word32)memSz, falcon) == 0; if (!isFalcon) { /* Try level 5 */ isFalcon = wc_falcon_set_level(falcon, 5) == 0 && wc_falcon_import_private_only(mem, (word32)memSz, falcon) == 0; } } else { /* Try level 1 */ isFalcon = wc_falcon_set_level(falcon, 1) == 0 && wc_falcon_import_public(mem, (word32)memSz, falcon) == 0; if (!isFalcon) { /* Try level 5 */ isFalcon = wc_falcon_set_level(falcon, 5) == 0 && wc_falcon_import_public(mem, (word32)memSz, falcon) == 0; } } wc_falcon_free(falcon); } #ifdef WOLFSSL_SMALL_STACK XFREE(falcon, NULL, DYNAMIC_TYPE_FALCON); #endif if (isFalcon) { /* Create a fake Falcon EVP_PKEY. In the future, we might integrate * Falcon into the compatibility layer. */ pkey = wolfSSL_EVP_PKEY_new(); if (pkey == NULL) { WOLFSSL_MSG("Falcon wolfSSL_EVP_PKEY_new error"); return NULL; } pkey->type = EVP_PKEY_FALCON; pkey->pkey.ptr = NULL; pkey->pkey_sz = 0; return pkey; } } #endif /* HAVE_PQC */ if (pkey == NULL) { WOLFSSL_MSG("wolfSSL_d2i_PUBKEY couldn't determine key type"); } return pkey; } #endif /* OPENSSL_EXTRA || WPA_SMALL */ #ifdef OPENSSL_EXTRA WOLFSSL_PKCS8_PRIV_KEY_INFO* wolfSSL_d2i_PKCS8_PKEY( WOLFSSL_PKCS8_PRIV_KEY_INFO** pkey, const unsigned char** keyBuf, long keyLen) { WOLFSSL_PKCS8_PRIV_KEY_INFO* pkcs8 = NULL; #ifdef WOLFSSL_PEM_TO_DER int ret; DerBuffer* der = NULL; if (keyBuf == NULL || *keyBuf == NULL || keyLen <= 0) { WOLFSSL_MSG("Bad key PEM/DER args"); return NULL; } ret = PemToDer(*keyBuf, keyLen, PRIVATEKEY_TYPE, &der, NULL, NULL, NULL); if (ret < 0) { WOLFSSL_MSG("Not PEM format"); ret = AllocDer(&der, (word32)keyLen, PRIVATEKEY_TYPE, NULL); if (ret == 0) { XMEMCPY(der->buffer, *keyBuf, keyLen); } } if (ret == 0) { /* Verify this is PKCS8 Key */ word32 inOutIdx = 0; word32 algId; ret = ToTraditionalInline_ex(der->buffer, &inOutIdx, der->length, &algId); if (ret >= 0) { ret = 0; /* good DER */ } } if (ret == 0) { pkcs8 = wolfSSL_EVP_PKEY_new(); if (pkcs8 == NULL) ret = MEMORY_E; } if (ret == 0) { pkcs8->pkey.ptr = (char*)XMALLOC(der->length, NULL, DYNAMIC_TYPE_PUBLIC_KEY); if (pkcs8->pkey.ptr == NULL) ret = MEMORY_E; } if (ret == 0) { XMEMCPY(pkcs8->pkey.ptr, der->buffer, der->length); pkcs8->pkey_sz = der->length; } FreeDer(&der); if (ret != 0) { wolfSSL_EVP_PKEY_free(pkcs8); pkcs8 = NULL; } if (pkey != NULL) { *pkey = pkcs8; } #else (void)bio; (void)pkey; #endif /* WOLFSSL_PEM_TO_DER */ return pkcs8; } #ifndef NO_BIO /* put SSL type in extra for now, not very common */ /* Converts a DER format key read from "bio" to a PKCS8 structure. * * bio input bio to read DER from * pkey If not NULL then this pointer will be overwritten with a new PKCS8 * structure. * * returns a WOLFSSL_PKCS8_PRIV_KEY_INFO pointer on success and NULL in fail * case. */ WOLFSSL_PKCS8_PRIV_KEY_INFO* wolfSSL_d2i_PKCS8_PKEY_bio(WOLFSSL_BIO* bio, WOLFSSL_PKCS8_PRIV_KEY_INFO** pkey) { WOLFSSL_PKCS8_PRIV_KEY_INFO* pkcs8 = NULL; #ifdef WOLFSSL_PEM_TO_DER unsigned char* mem = NULL; int memSz; WOLFSSL_ENTER("wolfSSL_d2i_PKCS8_PKEY_bio"); if (bio == NULL) { return NULL; } if ((memSz = wolfSSL_BIO_get_mem_data(bio, &mem)) < 0) { return NULL; } pkcs8 = wolfSSL_d2i_PKCS8_PKEY(pkey, (const unsigned char**)&mem, memSz); #else (void)bio; (void)pkey; #endif /* WOLFSSL_PEM_TO_DER */ return pkcs8; } /* expecting DER format public key * * bio input bio to read DER from * out If not NULL then this pointer will be overwritten with a new * WOLFSSL_EVP_PKEY pointer * * returns a WOLFSSL_EVP_PKEY pointer on success and NULL in fail case. */ WOLFSSL_EVP_PKEY* wolfSSL_d2i_PUBKEY_bio(WOLFSSL_BIO* bio, WOLFSSL_EVP_PKEY** out) { unsigned char* mem; long memSz; WOLFSSL_EVP_PKEY* pkey = NULL; WOLFSSL_ENTER("wolfSSL_d2i_PUBKEY_bio()"); if (bio == NULL) { return NULL; } (void)out; memSz = wolfSSL_BIO_get_len(bio); if (memSz <= 0) { return NULL; } mem = (unsigned char*)XMALLOC(memSz, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); if (mem == NULL) { return NULL; } if (wolfSSL_BIO_read(bio, mem, (int)memSz) == memSz) { pkey = wolfSSL_d2i_PUBKEY(NULL, (const unsigned char**)&mem, memSz); if (out != NULL && pkey != NULL) { *out = pkey; } } XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); return pkey; } #endif /* !NO_BIO */ /* Converts a DER encoded public key to a WOLFSSL_EVP_PKEY structure. * * out pointer to new WOLFSSL_EVP_PKEY structure. Can be NULL * in DER buffer to convert * inSz size of in buffer * * returns a pointer to a new WOLFSSL_EVP_PKEY structure on success and NULL * on fail */ WOLFSSL_EVP_PKEY* wolfSSL_d2i_PUBKEY(WOLFSSL_EVP_PKEY** out, const unsigned char** in, long inSz) { WOLFSSL_ENTER("wolfSSL_d2i_PUBKEY"); return d2iGenericKey(out, in, inSz, 0); } /* helper function to get raw pointer to DER buffer from WOLFSSL_EVP_PKEY */ static int wolfSSL_EVP_PKEY_get_der(const WOLFSSL_EVP_PKEY* key, unsigned char** der) { unsigned char* pt; int sz; word16 pkcs8HeaderSz; if (!key || !key->pkey_sz) return WOLFSSL_FATAL_ERROR; /* return the key without PKCS8 for compatibility */ /* if pkcs8HeaderSz is invalid, use 0 and return all of pkey */ pkcs8HeaderSz = 0; if (key->pkey_sz > key->pkcs8HeaderSz) pkcs8HeaderSz = key->pkcs8HeaderSz; sz = key->pkey_sz - pkcs8HeaderSz; if (der) { pt = (unsigned char*)key->pkey.ptr; if (*der) { /* since this function signature has no size value passed in it is * assumed that the user has allocated a large enough buffer */ XMEMCPY(*der, pt + pkcs8HeaderSz, sz); *der += sz; } else { *der = (unsigned char*)XMALLOC(sz, NULL, DYNAMIC_TYPE_OPENSSL); if (*der == NULL) { return WOLFSSL_FATAL_ERROR; } XMEMCPY(*der, pt + pkcs8HeaderSz, sz); } } return sz; } int wolfSSL_i2d_PUBKEY(const WOLFSSL_EVP_PKEY *key, unsigned char **der) { return wolfSSL_EVP_PKEY_get_der(key, der); } static WOLFSSL_EVP_PKEY* _d2i_PublicKey(int type, WOLFSSL_EVP_PKEY** out, const unsigned char **in, long inSz, int priv) { int ret = 0; word32 idx = 0, algId; word16 pkcs8HeaderSz = 0; WOLFSSL_EVP_PKEY* local; int opt; (void)opt; if (in == NULL || inSz < 0) { WOLFSSL_MSG("Bad argument"); return NULL; } if (priv == 1) { /* Check if input buffer has PKCS8 header. In the case that it does not * have a PKCS8 header then do not error out. */ if ((ret = ToTraditionalInline_ex((const byte*)(*in), &idx, (word32)inSz, &algId)) > 0) { WOLFSSL_MSG("Found PKCS8 header"); pkcs8HeaderSz = (word16)idx; if ((type == EVP_PKEY_RSA && algId != RSAk) || (type == EVP_PKEY_EC && algId != ECDSAk) || (type == EVP_PKEY_DSA && algId != DSAk) || (type == EVP_PKEY_DH && algId != DHk)) { WOLFSSL_MSG("PKCS8 does not match EVP key type"); return NULL; } (void)idx; /* not used */ } else { if (ret != ASN_PARSE_E) { WOLFSSL_MSG("Unexpected error with trying to remove PKCS8 " "header"); return NULL; } } } if (out != NULL && *out != NULL) { wolfSSL_EVP_PKEY_free(*out); *out = NULL; } local = wolfSSL_EVP_PKEY_new(); if (local == NULL) { return NULL; } local->type = type; local->pkey_sz = (int)inSz; local->pkcs8HeaderSz = pkcs8HeaderSz; local->pkey.ptr = (char*)XMALLOC(inSz, NULL, DYNAMIC_TYPE_PUBLIC_KEY); if (local->pkey.ptr == NULL) { wolfSSL_EVP_PKEY_free(local); local = NULL; return NULL; } else { XMEMCPY(local->pkey.ptr, *in, inSz); } switch (type) { #ifndef NO_RSA case EVP_PKEY_RSA: local->ownRsa = 1; local->rsa = wolfSSL_RSA_new(); if (local->rsa == NULL) { wolfSSL_EVP_PKEY_free(local); return NULL; } opt = priv ? WOLFSSL_RSA_LOAD_PRIVATE : WOLFSSL_RSA_LOAD_PUBLIC; if (wolfSSL_RSA_LoadDer_ex(local->rsa, (const unsigned char*)local->pkey.ptr, local->pkey_sz, opt) != WOLFSSL_SUCCESS) { wolfSSL_EVP_PKEY_free(local); return NULL; } break; #endif /* NO_RSA */ #ifdef HAVE_ECC case EVP_PKEY_EC: local->ownEcc = 1; local->ecc = wolfSSL_EC_KEY_new(); if (local->ecc == NULL) { wolfSSL_EVP_PKEY_free(local); return NULL; } opt = priv ? WOLFSSL_EC_KEY_LOAD_PRIVATE : WOLFSSL_EC_KEY_LOAD_PUBLIC; if (wolfSSL_EC_KEY_LoadDer_ex(local->ecc, (const unsigned char*)local->pkey.ptr, local->pkey_sz, opt) != WOLFSSL_SUCCESS) { wolfSSL_EVP_PKEY_free(local); return NULL; } break; #endif /* HAVE_ECC */ #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) || defined(WOLFSSL_OPENSSH) #ifndef NO_DSA case EVP_PKEY_DSA: local->ownDsa = 1; local->dsa = wolfSSL_DSA_new(); if (local->dsa == NULL) { wolfSSL_EVP_PKEY_free(local); return NULL; } opt = priv ? WOLFSSL_DSA_LOAD_PRIVATE : WOLFSSL_DSA_LOAD_PUBLIC; if (wolfSSL_DSA_LoadDer_ex(local->dsa, (const unsigned char*)local->pkey.ptr, local->pkey_sz, opt) != WOLFSSL_SUCCESS) { wolfSSL_EVP_PKEY_free(local); return NULL; } break; #endif /* NO_DSA */ #ifndef NO_DH #if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2)) case EVP_PKEY_DH: local->ownDh = 1; local->dh = wolfSSL_DH_new(); if (local->dh == NULL) { wolfSSL_EVP_PKEY_free(local); return NULL; } if (wolfSSL_DH_LoadDer(local->dh, (const unsigned char*)local->pkey.ptr, local->pkey_sz) != WOLFSSL_SUCCESS) { wolfSSL_EVP_PKEY_free(local); return NULL; } break; #endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */ #endif /* HAVE_DH */ #endif /* WOLFSSL_QT || OPENSSL_ALL || WOLFSSL_OPENSSH */ default: WOLFSSL_MSG("Unsupported key type"); wolfSSL_EVP_PKEY_free(local); return NULL; } /* advance pointer with success */ if (local != NULL) { if (local->pkey_sz <= (int)inSz) { *in += local->pkey_sz; } if (out != NULL) { *out = local; } } return local; } WOLFSSL_EVP_PKEY* wolfSSL_d2i_PublicKey(int type, WOLFSSL_EVP_PKEY** out, const unsigned char **in, long inSz) { WOLFSSL_ENTER("wolfSSL_d2i_PublicKey"); return _d2i_PublicKey(type, out, in, inSz, 0); } /* Reads in a DER format key. If PKCS8 headers are found they are stripped off. * * type type of key * out newly created WOLFSSL_EVP_PKEY structure * in pointer to input key DER * inSz size of in buffer * * On success a non null pointer is returned and the pointer in is advanced the * same number of bytes read. */ WOLFSSL_EVP_PKEY* wolfSSL_d2i_PrivateKey(int type, WOLFSSL_EVP_PKEY** out, const unsigned char **in, long inSz) { WOLFSSL_ENTER("wolfSSL_d2i_PrivateKey"); return _d2i_PublicKey(type, out, in, inSz, 1); } #ifdef WOLF_PRIVATE_KEY_ID /* Create an EVP structure for use with crypto callbacks */ WOLFSSL_EVP_PKEY* wolfSSL_d2i_PrivateKey_id(int type, WOLFSSL_EVP_PKEY** out, void* heap, int devId) { WOLFSSL_EVP_PKEY* local; if (out != NULL && *out != NULL) { wolfSSL_EVP_PKEY_free(*out); *out = NULL; } local = wolfSSL_EVP_PKEY_new_ex(heap); if (local == NULL) { return NULL; } local->type = type; local->pkey_sz = 0; local->pkcs8HeaderSz = 0; switch (type) { #ifndef NO_RSA case EVP_PKEY_RSA: { RsaKey* key; local->ownRsa = 1; local->rsa = wolfSSL_RSA_new_ex(heap, devId); if (local->rsa == NULL) { wolfSSL_EVP_PKEY_free(local); return NULL; } key = (RsaKey*)local->rsa->internal; #ifdef WOLF_CRYPTO_CB key->devId = devId; #endif (void)key; local->rsa->inSet = 1; break; } #endif /* !NO_RSA */ #ifdef HAVE_ECC case EVP_PKEY_EC: { ecc_key* key; local->ownEcc = 1; local->ecc = wolfSSL_EC_KEY_new_ex(heap, devId); if (local->ecc == NULL) { wolfSSL_EVP_PKEY_free(local); return NULL; } key = (ecc_key*)local->ecc->internal; #ifdef WOLF_CRYPTO_CB key->devId = devId; #endif key->type = ECC_PRIVATEKEY; /* key is required to have a key size / curve set, although * actual one used is determined by devId callback function */ wc_ecc_set_curve(key, ECDHE_SIZE, ECC_CURVE_DEF); local->ecc->inSet = 1; break; } #endif /* HAVE_ECC */ default: WOLFSSL_MSG("Unsupported private key id type"); wolfSSL_EVP_PKEY_free(local); return NULL; } if (local != NULL && out != NULL) { *out = local; } return local; } #endif /* WOLF_PRIVATE_KEY_ID */ #ifndef NO_CERTS // NOLINT(readability-redundant-preprocessor) #ifndef NO_CHECK_PRIVATE_KEY /* Check private against public in certificate for match * * ssl WOLFSSL structure to check private key in * * Returns WOLFSSL_SUCCESS on good private key * WOLFSSL_FAILURE if mismatched. */ int wolfSSL_check_private_key(const WOLFSSL* ssl) { if (ssl == NULL) { return WOLFSSL_FAILURE; } return check_cert_key(ssl->buffers.certificate, ssl->buffers.key, ssl->heap, ssl->buffers.keyDevId, ssl->buffers.keyLabel, ssl->buffers.keyId); } #endif /* !NO_CHECK_PRIVATE_KEY */ #if defined(OPENSSL_ALL) int wolfSSL_ASN1_BIT_STRING_set_bit(WOLFSSL_ASN1_BIT_STRING* str, int pos, int val) { int bytes_cnt, bit; byte* temp; if (!str || (val != 0 && val != 1) || pos < 0) { return WOLFSSL_FAILURE; } bytes_cnt = pos/8; bit = 1<<(7-(pos%8)); if (bytes_cnt+1 > str->length) { if (!(temp = (byte*)XREALLOC(str->data, bytes_cnt+1, NULL, DYNAMIC_TYPE_OPENSSL))) { return WOLFSSL_FAILURE; } XMEMSET(temp+str->length, 0, bytes_cnt+1 - str->length); str->data = temp; str->length = bytes_cnt+1; } str->data[bytes_cnt] &= ~bit; str->data[bytes_cnt] |= val ? bit : 0; return WOLFSSL_SUCCESS; } #endif /* OPENSSL_ALL */ #endif /* !NO_CERTS */ #endif /* OPENSSL_EXTRA */ #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) WOLFSSL_ASN1_BIT_STRING* wolfSSL_ASN1_BIT_STRING_new(void) { WOLFSSL_ASN1_BIT_STRING* str; str = (WOLFSSL_ASN1_BIT_STRING*)XMALLOC(sizeof(WOLFSSL_ASN1_BIT_STRING), NULL, DYNAMIC_TYPE_OPENSSL); if (str) { XMEMSET(str, 0, sizeof(WOLFSSL_ASN1_BIT_STRING)); } return str; } void wolfSSL_ASN1_BIT_STRING_free(WOLFSSL_ASN1_BIT_STRING* str) { if (str) { if (str->data) { XFREE(str->data, NULL, DYNAMIC_TYPE_OPENSSL); str->data = NULL; } XFREE(str, NULL, DYNAMIC_TYPE_OPENSSL); } } int wolfSSL_ASN1_BIT_STRING_get_bit(const WOLFSSL_ASN1_BIT_STRING* str, int i) { if (!str || !str->data || str->length <= (i/8) || i < 0) { return WOLFSSL_FAILURE; } return (str->data[i/8] & (1<<(7-(i%8)))) ? 1 : 0; } #endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */ #ifdef OPENSSL_EXTRA int wolfSSL_use_PrivateKey(WOLFSSL* ssl, WOLFSSL_EVP_PKEY* pkey) { WOLFSSL_ENTER("wolfSSL_use_PrivateKey"); if (ssl == NULL || pkey == NULL ) { return WOLFSSL_FAILURE; } return wolfSSL_use_PrivateKey_buffer(ssl, (unsigned char*)pkey->pkey.ptr, pkey->pkey_sz, WOLFSSL_FILETYPE_ASN1); } int wolfSSL_use_PrivateKey_ASN1(int pri, WOLFSSL* ssl, const unsigned char* der, long derSz) { WOLFSSL_ENTER("wolfSSL_use_PrivateKey_ASN1"); if (ssl == NULL || der == NULL ) { return WOLFSSL_FAILURE; } (void)pri; /* type of private key */ return wolfSSL_use_PrivateKey_buffer(ssl, der, derSz, WOLFSSL_FILETYPE_ASN1); } /****************************************************************************** * wolfSSL_CTX_use_PrivateKey_ASN1 - loads a private key buffer into the SSL ctx * * RETURNS: * returns WOLFSSL_SUCCESS on success, otherwise returns WOLFSSL_FAILURE */ int wolfSSL_CTX_use_PrivateKey_ASN1(int pri, WOLFSSL_CTX* ctx, unsigned char* der, long derSz) { WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey_ASN1"); if (ctx == NULL || der == NULL ) { return WOLFSSL_FAILURE; } (void)pri; /* type of private key */ return wolfSSL_CTX_use_PrivateKey_buffer(ctx, der, derSz, WOLFSSL_FILETYPE_ASN1); } #ifndef NO_RSA int wolfSSL_use_RSAPrivateKey_ASN1(WOLFSSL* ssl, unsigned char* der, long derSz) { WOLFSSL_ENTER("wolfSSL_use_RSAPrivateKey_ASN1"); if (ssl == NULL || der == NULL ) { return WOLFSSL_FAILURE; } return wolfSSL_use_PrivateKey_buffer(ssl, der, derSz, WOLFSSL_FILETYPE_ASN1); } #endif int wolfSSL_use_certificate(WOLFSSL* ssl, WOLFSSL_X509* x509) { long idx; WOLFSSL_ENTER("wolfSSL_use_certificate"); if (x509 != NULL && ssl != NULL && x509->derCert != NULL) { if (ProcessBuffer(NULL, x509->derCert->buffer, x509->derCert->length, WOLFSSL_FILETYPE_ASN1, CERT_TYPE, ssl, &idx, 0, GET_VERIFY_SETTING_SSL(ssl)) == WOLFSSL_SUCCESS) { return WOLFSSL_SUCCESS; } } (void)idx; return WOLFSSL_FAILURE; } #endif /* OPENSSL_EXTRA */ int wolfSSL_use_certificate_ASN1(WOLFSSL* ssl, const unsigned char* der, int derSz) { long idx; WOLFSSL_ENTER("wolfSSL_use_certificate_ASN1"); if (der != NULL && ssl != NULL) { if (ProcessBuffer(NULL, der, derSz, WOLFSSL_FILETYPE_ASN1, CERT_TYPE, ssl, &idx, 0, GET_VERIFY_SETTING_SSL(ssl)) == WOLFSSL_SUCCESS) { return WOLFSSL_SUCCESS; } } (void)idx; return WOLFSSL_FAILURE; } #ifndef NO_FILESYSTEM WOLFSSL_ABI int wolfSSL_use_certificate_file(WOLFSSL* ssl, const char* file, int format) { WOLFSSL_ENTER("wolfSSL_use_certificate_file"); if (ssl == NULL) { return BAD_FUNC_ARG; } if (ProcessFile(ssl->ctx, file, format, CERT_TYPE, ssl, 0, NULL, GET_VERIFY_SETTING_SSL(ssl)) == WOLFSSL_SUCCESS) { return WOLFSSL_SUCCESS; } return WOLFSSL_FAILURE; } WOLFSSL_ABI int wolfSSL_use_PrivateKey_file(WOLFSSL* ssl, const char* file, int format) { WOLFSSL_ENTER("wolfSSL_use_PrivateKey_file"); if (ssl == NULL) { return BAD_FUNC_ARG; } if (ProcessFile(ssl->ctx, file, format, PRIVATEKEY_TYPE, ssl, 0, NULL, GET_VERIFY_SETTING_SSL(ssl)) == WOLFSSL_SUCCESS) { return WOLFSSL_SUCCESS; } return WOLFSSL_FAILURE; } WOLFSSL_ABI int wolfSSL_use_certificate_chain_file(WOLFSSL* ssl, const char* file) { /* process up to MAX_CHAIN_DEPTH plus subject cert */ WOLFSSL_ENTER("wolfSSL_use_certificate_chain_file"); if (ssl == NULL) { return BAD_FUNC_ARG; } if (ProcessFile(ssl->ctx, file, WOLFSSL_FILETYPE_PEM, CERT_TYPE, ssl, 1, NULL, GET_VERIFY_SETTING_SSL(ssl)) == WOLFSSL_SUCCESS) { return WOLFSSL_SUCCESS; } return WOLFSSL_FAILURE; } int wolfSSL_use_certificate_chain_file_format(WOLFSSL* ssl, const char* file, int format) { /* process up to MAX_CHAIN_DEPTH plus subject cert */ WOLFSSL_ENTER("wolfSSL_use_certificate_chain_file_format"); if (ssl == NULL) { return BAD_FUNC_ARG; } if (ProcessFile(ssl->ctx, file, format, CERT_TYPE, ssl, 1, NULL, GET_VERIFY_SETTING_SSL(ssl)) == WOLFSSL_SUCCESS) { return WOLFSSL_SUCCESS; } return WOLFSSL_FAILURE; } #endif /* !NO_FILESYSTEM */ #ifdef HAVE_ECC /* Set Temp CTX EC-DHE size in octets, can be 14 - 66 (112 - 521 bit) */ int wolfSSL_CTX_SetTmpEC_DHE_Sz(WOLFSSL_CTX* ctx, word16 sz) { if (ctx == NULL) return BAD_FUNC_ARG; /* if 0 then get from loaded private key */ if (sz == 0) { /* applies only to ECDSA */ if (ctx->privateKeyType != ecc_dsa_sa_algo) return WOLFSSL_SUCCESS; if (ctx->privateKeySz == 0) { WOLFSSL_MSG("Must set private key/cert first"); return BAD_FUNC_ARG; } sz = (word16)ctx->privateKeySz; } /* check size */ if (sz < ECC_MINSIZE || sz > ECC_MAXSIZE) return BAD_FUNC_ARG; ctx->eccTempKeySz = sz; return WOLFSSL_SUCCESS; } /* Set Temp SSL EC-DHE size in octets, can be 14 - 66 (112 - 521 bit) */ int wolfSSL_SetTmpEC_DHE_Sz(WOLFSSL* ssl, word16 sz) { if (ssl == NULL) return BAD_FUNC_ARG; /* check size */ if (sz < ECC_MINSIZE || sz > ECC_MAXSIZE) return BAD_FUNC_ARG; ssl->eccTempKeySz = sz; return WOLFSSL_SUCCESS; } #endif /* HAVE_ECC */ #ifdef OPENSSL_EXTRA #ifndef NO_FILESYSTEM int wolfSSL_CTX_use_RSAPrivateKey_file(WOLFSSL_CTX* ctx,const char* file, int format) { WOLFSSL_ENTER("SSL_CTX_use_RSAPrivateKey_file"); return wolfSSL_CTX_use_PrivateKey_file(ctx, file, format); } int wolfSSL_use_RSAPrivateKey_file(WOLFSSL* ssl, const char* file, int format) { WOLFSSL_ENTER("wolfSSL_use_RSAPrivateKey_file"); return wolfSSL_use_PrivateKey_file(ssl, file, format); } #endif /* NO_FILESYSTEM */ /* Copies the master secret over to out buffer. If outSz is 0 returns the size * of master secret. * * ses : a session from completed TLS/SSL handshake * out : buffer to hold copy of master secret * outSz : size of out buffer * returns : number of bytes copied into out buffer on success * less then or equal to 0 is considered a failure case */ int wolfSSL_SESSION_get_master_key(const WOLFSSL_SESSION* ses, unsigned char* out, int outSz) { int size; ses = ClientSessionToSession(ses); if (outSz == 0) { return SECRET_LEN; } if (ses == NULL || out == NULL || outSz < 0) { return 0; } if (outSz > SECRET_LEN) { size = SECRET_LEN; } else { size = outSz; } XMEMCPY(out, ses->masterSecret, size); return size; } int wolfSSL_SESSION_get_master_key_length(const WOLFSSL_SESSION* ses) { (void)ses; return SECRET_LEN; } #endif /* OPENSSL_EXTRA */ typedef struct { byte verifyPeer:1; byte verifyNone:1; byte failNoCert:1; byte failNoCertxPSK:1; byte verifyPostHandshake:1; } SetVerifyOptions; static SetVerifyOptions ModeToVerifyOptions(int mode) { SetVerifyOptions opts; XMEMSET(&opts, 0, sizeof(SetVerifyOptions)); if (mode != WOLFSSL_VERIFY_DEFAULT) { opts.verifyNone = (mode == WOLFSSL_VERIFY_NONE); if (!opts.verifyNone) { opts.verifyPeer = (mode & WOLFSSL_VERIFY_PEER) != 0; opts.failNoCertxPSK = (mode & WOLFSSL_VERIFY_FAIL_EXCEPT_PSK) != 0; opts.failNoCert = (mode & WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT) != 0; #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) opts.verifyPostHandshake = (mode & WOLFSSL_VERIFY_POST_HANDSHAKE) != 0; #endif } } return opts; } WOLFSSL_ABI void wolfSSL_CTX_set_verify(WOLFSSL_CTX* ctx, int mode, VerifyCallback vc) { SetVerifyOptions opts; WOLFSSL_ENTER("wolfSSL_CTX_set_verify"); if (ctx == NULL) return; opts = ModeToVerifyOptions(mode); ctx->verifyNone = opts.verifyNone; ctx->verifyPeer = opts.verifyPeer; ctx->failNoCert = opts.failNoCert; ctx->failNoCertxPSK = opts.failNoCertxPSK; #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) ctx->verifyPostHandshake = opts.verifyPostHandshake; #endif ctx->verifyCallback = vc; } #ifdef OPENSSL_ALL void wolfSSL_CTX_set_cert_verify_callback(WOLFSSL_CTX* ctx, CertVerifyCallback cb, void* arg) { WOLFSSL_ENTER("SSL_CTX_set_cert_verify_callback"); if (ctx == NULL) return; ctx->verifyCertCb = cb; ctx->verifyCertCbArg = arg; } #endif void wolfSSL_set_verify(WOLFSSL* ssl, int mode, VerifyCallback vc) { SetVerifyOptions opts; WOLFSSL_ENTER("wolfSSL_set_verify"); if (ssl == NULL) return; opts = ModeToVerifyOptions(mode); ssl->options.verifyNone = opts.verifyNone; ssl->options.verifyPeer = opts.verifyPeer; ssl->options.failNoCert = opts.failNoCert; ssl->options.failNoCertxPSK = opts.failNoCertxPSK; #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) ssl->options.verifyPostHandshake = opts.verifyPostHandshake; #endif ssl->verifyCallback = vc; } void wolfSSL_set_verify_result(WOLFSSL *ssl, long v) { WOLFSSL_ENTER("wolfSSL_set_verify_result"); if (ssl == NULL) return; #ifdef OPENSSL_ALL ssl->verifyCallbackResult = v; #else (void)v; WOLFSSL_STUB("wolfSSL_set_verify_result"); #endif } #if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && \ defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) /* For TLS v1.3 send handshake messages after handshake completes. */ /* Returns 1=WOLFSSL_SUCCESS or 0=WOLFSSL_FAILURE */ int wolfSSL_verify_client_post_handshake(WOLFSSL* ssl) { int ret = wolfSSL_request_certificate(ssl); if (ret != WOLFSSL_SUCCESS) { if (!IsAtLeastTLSv1_3(ssl->version)) { /* specific error of wrong version expected */ WOLFSSL_ERROR(UNSUPPORTED_PROTO_VERSION); } else { WOLFSSL_ERROR(ret); /* log the error in the error queue */ } } return (ret == WOLFSSL_SUCCESS) ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; } int wolfSSL_CTX_set_post_handshake_auth(WOLFSSL_CTX* ctx, int val) { int ret = wolfSSL_CTX_allow_post_handshake_auth(ctx); if (ret == 0) { ctx->postHandshakeAuth = (val != 0); } return (ret == 0) ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; } int wolfSSL_set_post_handshake_auth(WOLFSSL* ssl, int val) { int ret = wolfSSL_allow_post_handshake_auth(ssl); if (ret == 0) { ssl->options.postHandshakeAuth = (val != 0); } return (ret == 0) ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; } #endif /* OPENSSL_EXTRA && !NO_CERTS && WOLFSSL_TLS13 && WOLFSSL_POST_HANDSHAKE_AUTH */ /* store user ctx for verify callback */ void wolfSSL_SetCertCbCtx(WOLFSSL* ssl, void* ctx) { WOLFSSL_ENTER("wolfSSL_SetCertCbCtx"); if (ssl) ssl->verifyCbCtx = ctx; } /* store user ctx for verify callback */ void wolfSSL_CTX_SetCertCbCtx(WOLFSSL_CTX* ctx, void* userCtx) { WOLFSSL_ENTER("wolfSSL_CTX_SetCertCbCtx"); if (ctx) ctx->verifyCbCtx = userCtx; } /* store context CA Cache addition callback */ void wolfSSL_CTX_SetCACb(WOLFSSL_CTX* ctx, CallbackCACache cb) { if (ctx && ctx->cm) ctx->cm->caCacheCallback = cb; } #if defined(PERSIST_CERT_CACHE) #if !defined(NO_FILESYSTEM) /* Persist cert cache to file */ int wolfSSL_CTX_save_cert_cache(WOLFSSL_CTX* ctx, const char* fname) { WOLFSSL_ENTER("wolfSSL_CTX_save_cert_cache"); if (ctx == NULL || fname == NULL) return BAD_FUNC_ARG; return CM_SaveCertCache(ctx->cm, fname); } /* Persist cert cache from file */ int wolfSSL_CTX_restore_cert_cache(WOLFSSL_CTX* ctx, const char* fname) { WOLFSSL_ENTER("wolfSSL_CTX_restore_cert_cache"); if (ctx == NULL || fname == NULL) return BAD_FUNC_ARG; return CM_RestoreCertCache(ctx->cm, fname); } #endif /* NO_FILESYSTEM */ /* Persist cert cache to memory */ int wolfSSL_CTX_memsave_cert_cache(WOLFSSL_CTX* ctx, void* mem, int sz, int* used) { WOLFSSL_ENTER("wolfSSL_CTX_memsave_cert_cache"); if (ctx == NULL || mem == NULL || used == NULL || sz <= 0) return BAD_FUNC_ARG; return CM_MemSaveCertCache(ctx->cm, mem, sz, used); } /* Restore cert cache from memory */ int wolfSSL_CTX_memrestore_cert_cache(WOLFSSL_CTX* ctx, const void* mem, int sz) { WOLFSSL_ENTER("wolfSSL_CTX_memrestore_cert_cache"); if (ctx == NULL || mem == NULL || sz <= 0) return BAD_FUNC_ARG; return CM_MemRestoreCertCache(ctx->cm, mem, sz); } /* get how big the the cert cache save buffer needs to be */ int wolfSSL_CTX_get_cert_cache_memsize(WOLFSSL_CTX* ctx) { WOLFSSL_ENTER("wolfSSL_CTX_get_cert_cache_memsize"); if (ctx == NULL) return BAD_FUNC_ARG; return CM_GetCertCacheMemSize(ctx->cm); } #endif /* PERSIST_CERT_CACHE */ #endif /* !NO_CERTS */ #ifndef NO_SESSION_CACHE WOLFSSL_ABI WOLFSSL_SESSION* wolfSSL_get_session(WOLFSSL* ssl) { WOLFSSL_ENTER("SSL_get_session"); if (ssl) { #ifdef NO_SESSION_CACHE_REF return ssl->session; #else if (ssl->options.side == WOLFSSL_CLIENT_END) { /* On the client side we want to return a persistant reference for * backwards compatibility. */ #ifndef NO_CLIENT_CACHE if (ssl->clientSession) return (WOLFSSL_SESSION*)ssl->clientSession; else { /* Try to add a ClientCache entry to associate with the current * session. Ignore any session cache options. */ int error; const byte* id = NULL; byte idSz = 0; id = ssl->session->sessionID; idSz = ssl->session->sessionIDSz; if (ssl->session->haveAltSessionID) { id = ssl->session->altSessionID; idSz = ID_LEN; } error = AddSessionToCache(ssl->ctx, ssl->session, id, idSz, NULL, ssl->session->side, #ifdef HAVE_SESSION_TICKET ssl->session->ticketLen > 0, #else 0, #endif &ssl->clientSession); if (error == 0) return (WOLFSSL_SESSION*)ssl->clientSession; } #endif } else return ssl->session; #endif } return NULL; } /* The get1 version requires caller to call SSL_SESSION_free */ WOLFSSL_SESSION* wolfSSL_get1_session(WOLFSSL* ssl) { WOLFSSL_SESSION* sess = NULL; WOLFSSL_ENTER("SSL_get1_session"); if (ssl != NULL) { sess = ssl->session; if (sess != NULL) { /* increase reference count if allocated session */ if (sess->type == WOLFSSL_SESSION_TYPE_HEAP) { if (wolfSSL_SESSION_up_ref(sess) != WOLFSSL_SUCCESS) sess = NULL; } } } return sess; } /* * Sets the session object to use when establishing a TLS/SSL session using * the ssl object. Therefore, this function must be called before * wolfSSL_connect. The session object to use can be obtained in a previous * TLS/SSL connection using wolfSSL_get_session. * * This function rejects the session if it has been expired when this function * is called. Note that this expiration check is wolfSSL specific and differs * from OpenSSL return code behavior. * * By default, wolfSSL_set_session returns WOLFSSL_SUCCESS on successfully * setting the session, WOLFSSL_FAILURE on failure due to the session cache * being disabled, or the session has expired. * * To match OpenSSL return code behavior when session is expired, define * OPENSSL_EXTRA and WOLFSSL_ERROR_CODE_OPENSSL. This behavior will return * WOLFSSL_SUCCESS even when the session is expired and rejected. */ WOLFSSL_ABI int wolfSSL_set_session(WOLFSSL* ssl, WOLFSSL_SESSION* session) { WOLFSSL_ENTER("SSL_set_session"); if (session) return wolfSSL_SetSession(ssl, session); return WOLFSSL_FAILURE; } #ifndef NO_CLIENT_CACHE /* Associate client session with serverID, find existing or store for saving if newSession flag on, don't reuse existing session WOLFSSL_SUCCESS on ok */ int wolfSSL_SetServerID(WOLFSSL* ssl, const byte* id, int len, int newSession) { WOLFSSL_SESSION* session = NULL; WOLFSSL_ENTER("wolfSSL_SetServerID"); if (ssl == NULL || id == NULL || len <= 0) return BAD_FUNC_ARG; if (newSession == 0) { session = wolfSSL_GetSessionClient(ssl, id, len); if (session) { if (wolfSSL_SetSession(ssl, session) != WOLFSSL_SUCCESS) { #ifdef HAVE_EXT_CACHE wolfSSL_FreeSession(ssl->ctx, session); #endif WOLFSSL_MSG("wolfSSL_SetSession failed"); session = NULL; } } } if (session == NULL) { WOLFSSL_MSG("Valid ServerID not cached already"); ssl->session->idLen = (word16)min(SERVER_ID_LEN, (word32)len); XMEMCPY(ssl->session->serverID, id, ssl->session->idLen); } #ifdef HAVE_EXT_CACHE else { wolfSSL_FreeSession(ssl->ctx, session); } #endif return WOLFSSL_SUCCESS; } #endif /* !NO_CLIENT_CACHE */ #if defined(PERSIST_SESSION_CACHE) /* for persistence, if changes to layout need to increment and modify save_session_cache() and restore_session_cache and memory versions too */ #define WOLFSSL_CACHE_VERSION 2 /* Session Cache Header information */ typedef struct { int version; /* cache layout version id */ int rows; /* session rows */ int columns; /* session columns */ int sessionSz; /* sizeof WOLFSSL_SESSION */ } cache_header_t; /* current persistence layout is: 1) cache_header_t 2) SessionCache 3) ClientCache update WOLFSSL_CACHE_VERSION if change layout for the following PERSISTENT_SESSION_CACHE functions */ /* get how big the the session cache save buffer needs to be */ int wolfSSL_get_session_cache_memsize(void) { int sz = (int)(sizeof(SessionCache) + sizeof(cache_header_t)); #ifndef NO_CLIENT_CACHE sz += (int)(sizeof(ClientCache)); #endif return sz; } /* Persist session cache to memory */ int wolfSSL_memsave_session_cache(void* mem, int sz) { int i; cache_header_t cache_header; SessionRow* row = (SessionRow*)((byte*)mem + sizeof(cache_header)); WOLFSSL_ENTER("wolfSSL_memsave_session_cache"); if (sz < wolfSSL_get_session_cache_memsize()) { WOLFSSL_MSG("Memory buffer too small"); return BUFFER_E; } cache_header.version = WOLFSSL_CACHE_VERSION; cache_header.rows = SESSION_ROWS; cache_header.columns = SESSIONS_PER_ROW; cache_header.sessionSz = (int)sizeof(WOLFSSL_SESSION); XMEMCPY(mem, &cache_header, sizeof(cache_header)); #ifndef ENABLE_SESSION_CACHE_ROW_LOCK if (wc_LockMutex(&session_mutex) != 0) { WOLFSSL_MSG("Session cache mutex lock failed"); return BAD_MUTEX_E; } #endif for (i = 0; i < cache_header.rows; ++i) { #ifdef ENABLE_SESSION_CACHE_ROW_LOCK if (SESSION_ROW_LOCK(&SessionCache[i]) != 0) { WOLFSSL_MSG("Session row cache mutex lock failed"); return BAD_MUTEX_E; } #endif XMEMCPY(row++, &SessionCache[i], SIZEOF_SESSION_ROW); #ifdef ENABLE_SESSION_CACHE_ROW_LOCK SESSION_ROW_UNLOCK(&SessionCache[i]); #endif } #ifndef ENABLE_SESSION_CACHE_ROW_LOCK wc_UnLockMutex(&session_mutex); #endif #ifndef NO_CLIENT_CACHE if (wc_LockMutex(&clisession_mutex) != 0) { WOLFSSL_MSG("Client cache mutex lock failed"); return BAD_MUTEX_E; } XMEMCPY(row, ClientCache, sizeof(ClientCache)); wc_UnLockMutex(&clisession_mutex); #endif WOLFSSL_LEAVE("wolfSSL_memsave_session_cache", WOLFSSL_SUCCESS); return WOLFSSL_SUCCESS; } /* Restore the persistent session cache from memory */ int wolfSSL_memrestore_session_cache(const void* mem, int sz) { int i; cache_header_t cache_header; SessionRow* row = (SessionRow*)((byte*)mem + sizeof(cache_header)); WOLFSSL_ENTER("wolfSSL_memrestore_session_cache"); if (sz < wolfSSL_get_session_cache_memsize()) { WOLFSSL_MSG("Memory buffer too small"); return BUFFER_E; } XMEMCPY(&cache_header, mem, sizeof(cache_header)); if (cache_header.version != WOLFSSL_CACHE_VERSION || cache_header.rows != SESSION_ROWS || cache_header.columns != SESSIONS_PER_ROW || cache_header.sessionSz != (int)sizeof(WOLFSSL_SESSION)) { WOLFSSL_MSG("Session cache header match failed"); return CACHE_MATCH_ERROR; } #ifndef ENABLE_SESSION_CACHE_ROW_LOCK if (wc_LockMutex(&session_mutex) != 0) { WOLFSSL_MSG("Session cache mutex lock failed"); return BAD_MUTEX_E; } #endif for (i = 0; i < cache_header.rows; ++i) { #ifdef ENABLE_SESSION_CACHE_ROW_LOCK if (SESSION_ROW_LOCK(&SessionCache[i]) != 0) { WOLFSSL_MSG("Session row cache mutex lock failed"); return BAD_MUTEX_E; } #endif XMEMCPY(&SessionCache[i], row++, SIZEOF_SESSION_ROW); #ifdef ENABLE_SESSION_CACHE_ROW_LOCK SESSION_ROW_UNLOCK(&SessionCache[i]); #endif } #ifndef ENABLE_SESSION_CACHE_ROW_LOCK wc_UnLockMutex(&session_mutex); #endif #ifndef NO_CLIENT_CACHE if (wc_LockMutex(&clisession_mutex) != 0) { WOLFSSL_MSG("Client cache mutex lock failed"); return BAD_MUTEX_E; } XMEMCPY(ClientCache, row, sizeof(ClientCache)); wc_UnLockMutex(&clisession_mutex); #endif WOLFSSL_LEAVE("wolfSSL_memrestore_session_cache", WOLFSSL_SUCCESS); return WOLFSSL_SUCCESS; } #if !defined(NO_FILESYSTEM) /* Persist session cache to file */ /* doesn't use memsave because of additional memory use */ int wolfSSL_save_session_cache(const char *fname) { XFILE file; int ret; int rc = WOLFSSL_SUCCESS; int i; cache_header_t cache_header; WOLFSSL_ENTER("wolfSSL_save_session_cache"); file = XFOPEN(fname, "w+b"); if (file == XBADFILE) { WOLFSSL_MSG("Couldn't open session cache save file"); return WOLFSSL_BAD_FILE; } cache_header.version = WOLFSSL_CACHE_VERSION; cache_header.rows = SESSION_ROWS; cache_header.columns = SESSIONS_PER_ROW; cache_header.sessionSz = (int)sizeof(WOLFSSL_SESSION); /* cache header */ ret = (int)XFWRITE(&cache_header, sizeof cache_header, 1, file); if (ret != 1) { WOLFSSL_MSG("Session cache header file write failed"); XFCLOSE(file); return FWRITE_ERROR; } #ifndef ENABLE_SESSION_CACHE_ROW_LOCK if (wc_LockMutex(&session_mutex) != 0) { WOLFSSL_MSG("Session cache mutex lock failed"); XFCLOSE(file); return BAD_MUTEX_E; } #endif /* session cache */ for (i = 0; i < cache_header.rows; ++i) { #ifdef ENABLE_SESSION_CACHE_ROW_LOCK if (SESSION_ROW_LOCK(&SessionCache[i]) != 0) { WOLFSSL_MSG("Session row cache mutex lock failed"); XFCLOSE(file); return BAD_MUTEX_E; } #endif ret = (int)XFWRITE(&SessionCache[i], SIZEOF_SESSION_ROW, 1, file); #ifdef ENABLE_SESSION_CACHE_ROW_LOCK SESSION_ROW_UNLOCK(&SessionCache[i]); #endif if (ret != 1) { WOLFSSL_MSG("Session cache member file write failed"); rc = FWRITE_ERROR; break; } } #ifndef ENABLE_SESSION_CACHE_ROW_LOCK wc_UnLockMutex(&session_mutex); #endif #ifndef NO_CLIENT_CACHE /* client cache */ if (wc_LockMutex(&clisession_mutex) != 0) { WOLFSSL_MSG("Client cache mutex lock failed"); XFCLOSE(file); return BAD_MUTEX_E; } ret = (int)XFWRITE(ClientCache, sizeof(ClientCache), 1, file); if (ret != 1) { WOLFSSL_MSG("Client cache member file write failed"); rc = FWRITE_ERROR; } wc_UnLockMutex(&clisession_mutex); #endif /* !NO_CLIENT_CACHE */ XFCLOSE(file); WOLFSSL_LEAVE("wolfSSL_save_session_cache", rc); return rc; } /* Restore the persistent session cache from file */ /* doesn't use memstore because of additional memory use */ int wolfSSL_restore_session_cache(const char *fname) { XFILE file; int rc = WOLFSSL_SUCCESS; int ret; int i; cache_header_t cache_header; WOLFSSL_ENTER("wolfSSL_restore_session_cache"); file = XFOPEN(fname, "rb"); if (file == XBADFILE) { WOLFSSL_MSG("Couldn't open session cache save file"); return WOLFSSL_BAD_FILE; } /* cache header */ ret = (int)XFREAD(&cache_header, sizeof(cache_header), 1, file); if (ret != 1) { WOLFSSL_MSG("Session cache header file read failed"); XFCLOSE(file); return FREAD_ERROR; } if (cache_header.version != WOLFSSL_CACHE_VERSION || cache_header.rows != SESSION_ROWS || cache_header.columns != SESSIONS_PER_ROW || cache_header.sessionSz != (int)sizeof(WOLFSSL_SESSION)) { WOLFSSL_MSG("Session cache header match failed"); XFCLOSE(file); return CACHE_MATCH_ERROR; } #ifndef ENABLE_SESSION_CACHE_ROW_LOCK if (wc_LockMutex(&session_mutex) != 0) { WOLFSSL_MSG("Session cache mutex lock failed"); XFCLOSE(file); return BAD_MUTEX_E; } #endif /* session cache */ for (i = 0; i < cache_header.rows; ++i) { #ifdef ENABLE_SESSION_CACHE_ROW_LOCK if (SESSION_ROW_LOCK(&SessionCache[i]) != 0) { WOLFSSL_MSG("Session row cache mutex lock failed"); XFCLOSE(file); return BAD_MUTEX_E; } #endif ret = (int)XFREAD(&SessionCache[i], SIZEOF_SESSION_ROW, 1, file); #ifdef ENABLE_SESSION_CACHE_ROW_LOCK SESSION_ROW_UNLOCK(&SessionCache[i]); #endif if (ret != 1) { WOLFSSL_MSG("Session cache member file read failed"); XMEMSET(SessionCache, 0, sizeof SessionCache); rc = FREAD_ERROR; break; } } #ifndef ENABLE_SESSION_CACHE_ROW_LOCK wc_UnLockMutex(&session_mutex); #endif #ifndef NO_CLIENT_CACHE /* client cache */ if (wc_LockMutex(&clisession_mutex) != 0) { WOLFSSL_MSG("Client cache mutex lock failed"); XFCLOSE(file); return BAD_MUTEX_E; } ret = (int)XFREAD(ClientCache, sizeof(ClientCache), 1, file); if (ret != 1) { WOLFSSL_MSG("Client cache member file read failed"); XMEMSET(ClientCache, 0, sizeof ClientCache); rc = FREAD_ERROR; } wc_UnLockMutex(&clisession_mutex); #endif /* !NO_CLIENT_CACHE */ XFCLOSE(file); WOLFSSL_LEAVE("wolfSSL_restore_session_cache", rc); return rc; } #endif /* !NO_FILESYSTEM */ #endif /* PERSIST_SESSION_CACHE */ #endif /* NO_SESSION_CACHE */ void wolfSSL_load_error_strings(void) { /* compatibility only */ } int wolfSSL_library_init(void) { WOLFSSL_ENTER("SSL_library_init"); if (wolfSSL_Init() == WOLFSSL_SUCCESS) return WOLFSSL_SUCCESS; else return WOLFSSL_FATAL_ERROR; } #ifdef HAVE_SECRET_CALLBACK int wolfSSL_set_session_secret_cb(WOLFSSL* ssl, SessionSecretCb cb, void* ctx) { WOLFSSL_ENTER("wolfSSL_set_session_secret_cb"); if (ssl == NULL) return WOLFSSL_FATAL_ERROR; ssl->sessionSecretCb = cb; ssl->sessionSecretCtx = ctx; if (cb != NULL) { /* If using a pre-set key, assume session resumption. */ ssl->session->sessionIDSz = 0; ssl->options.resuming = 1; } return WOLFSSL_SUCCESS; } #endif #ifndef NO_SESSION_CACHE /* on by default if built in but allow user to turn off */ WOLFSSL_ABI long wolfSSL_CTX_set_session_cache_mode(WOLFSSL_CTX* ctx, long mode) { WOLFSSL_ENTER("SSL_CTX_set_session_cache_mode"); if (ctx == NULL) return WOLFSSL_FAILURE; if (mode == WOLFSSL_SESS_CACHE_OFF) ctx->sessionCacheOff = 1; if ((mode & WOLFSSL_SESS_CACHE_NO_AUTO_CLEAR) != 0) ctx->sessionCacheFlushOff = 1; #ifdef HAVE_EXT_CACHE if ((mode & WOLFSSL_SESS_CACHE_NO_INTERNAL_STORE) != 0) ctx->internalCacheOff = 1; if ((mode & WOLFSSL_SESS_CACHE_NO_INTERNAL_LOOKUP) != 0) ctx->internalCacheLookupOff = 1; #endif return WOLFSSL_SUCCESS; } #endif /* NO_SESSION_CACHE */ #if !defined(NO_CERTS) #if defined(PERSIST_CERT_CACHE) #define WOLFSSL_CACHE_CERT_VERSION 1 typedef struct { int version; /* cache cert layout version id */ int rows; /* hash table rows, CA_TABLE_SIZE */ int columns[CA_TABLE_SIZE]; /* columns per row on list */ int signerSz; /* sizeof Signer object */ } CertCacheHeader; /* current cert persistence layout is: 1) CertCacheHeader 2) caTable update WOLFSSL_CERT_CACHE_VERSION if change layout for the following PERSIST_CERT_CACHE functions */ /* Return memory needed to persist this signer, have lock */ static WC_INLINE int GetSignerMemory(Signer* signer) { int sz = sizeof(signer->pubKeySize) + sizeof(signer->keyOID) + sizeof(signer->nameLen) + sizeof(signer->subjectNameHash); #if !defined(NO_SKID) sz += (int)sizeof(signer->subjectKeyIdHash); #endif /* add dynamic bytes needed */ sz += signer->pubKeySize; sz += signer->nameLen; return sz; } /* Return memory needed to persist this row, have lock */ static WC_INLINE int GetCertCacheRowMemory(Signer* row) { int sz = 0; while (row) { sz += GetSignerMemory(row); row = row->next; } return sz; } /* get the size of persist cert cache, have lock */ static WC_INLINE int GetCertCacheMemSize(WOLFSSL_CERT_MANAGER* cm) { int sz; int i; sz = sizeof(CertCacheHeader); for (i = 0; i < CA_TABLE_SIZE; i++) sz += GetCertCacheRowMemory(cm->caTable[i]); return sz; } /* Store cert cache header columns with number of items per list, have lock */ static WC_INLINE void SetCertHeaderColumns(WOLFSSL_CERT_MANAGER* cm, int* columns) { int i; Signer* row; for (i = 0; i < CA_TABLE_SIZE; i++) { int count = 0; row = cm->caTable[i]; while (row) { ++count; row = row->next; } columns[i] = count; } } /* Restore whole cert row from memory, have lock, return bytes consumed, < 0 on error, have lock */ static WC_INLINE int RestoreCertRow(WOLFSSL_CERT_MANAGER* cm, byte* current, int row, int listSz, const byte* end) { int idx = 0; if (listSz < 0) { WOLFSSL_MSG("Row header corrupted, negative value"); return PARSE_ERROR; } while (listSz) { Signer* signer; byte* publicKey; byte* start = current + idx; /* for end checks on this signer */ int minSz = sizeof(signer->pubKeySize) + sizeof(signer->keyOID) + sizeof(signer->nameLen) + sizeof(signer->subjectNameHash); #ifndef NO_SKID minSz += (int)sizeof(signer->subjectKeyIdHash); #endif if (start + minSz > end) { WOLFSSL_MSG("Would overread restore buffer"); return BUFFER_E; } signer = MakeSigner(cm->heap); if (signer == NULL) return MEMORY_E; /* pubKeySize */ XMEMCPY(&signer->pubKeySize, current + idx, sizeof(signer->pubKeySize)); idx += (int)sizeof(signer->pubKeySize); /* keyOID */ XMEMCPY(&signer->keyOID, current + idx, sizeof(signer->keyOID)); idx += (int)sizeof(signer->keyOID); /* publicKey */ if (start + minSz + signer->pubKeySize > end) { WOLFSSL_MSG("Would overread restore buffer"); FreeSigner(signer, cm->heap); return BUFFER_E; } publicKey = (byte*)XMALLOC(signer->pubKeySize, cm->heap, DYNAMIC_TYPE_KEY); if (publicKey == NULL) { FreeSigner(signer, cm->heap); return MEMORY_E; } XMEMCPY(publicKey, current + idx, signer->pubKeySize); signer->publicKey = publicKey; idx += signer->pubKeySize; /* nameLen */ XMEMCPY(&signer->nameLen, current + idx, sizeof(signer->nameLen)); idx += (int)sizeof(signer->nameLen); /* name */ if (start + minSz + signer->pubKeySize + signer->nameLen > end) { WOLFSSL_MSG("Would overread restore buffer"); FreeSigner(signer, cm->heap); return BUFFER_E; } signer->name = (char*)XMALLOC(signer->nameLen, cm->heap, DYNAMIC_TYPE_SUBJECT_CN); if (signer->name == NULL) { FreeSigner(signer, cm->heap); return MEMORY_E; } XMEMCPY(signer->name, current + idx, signer->nameLen); idx += signer->nameLen; /* subjectNameHash */ XMEMCPY(signer->subjectNameHash, current + idx, SIGNER_DIGEST_SIZE); idx += SIGNER_DIGEST_SIZE; #ifndef NO_SKID /* subjectKeyIdHash */ XMEMCPY(signer->subjectKeyIdHash, current + idx,SIGNER_DIGEST_SIZE); idx += SIGNER_DIGEST_SIZE; #endif signer->next = cm->caTable[row]; cm->caTable[row] = signer; --listSz; } return idx; } /* Store whole cert row into memory, have lock, return bytes added */ static WC_INLINE int StoreCertRow(WOLFSSL_CERT_MANAGER* cm, byte* current, int row) { int added = 0; Signer* list = cm->caTable[row]; while (list) { XMEMCPY(current + added, &list->pubKeySize, sizeof(list->pubKeySize)); added += (int)sizeof(list->pubKeySize); XMEMCPY(current + added, &list->keyOID, sizeof(list->keyOID)); added += (int)sizeof(list->keyOID); XMEMCPY(current + added, list->publicKey, list->pubKeySize); added += list->pubKeySize; XMEMCPY(current + added, &list->nameLen, sizeof(list->nameLen)); added += (int)sizeof(list->nameLen); XMEMCPY(current + added, list->name, list->nameLen); added += list->nameLen; XMEMCPY(current + added, list->subjectNameHash, SIGNER_DIGEST_SIZE); added += SIGNER_DIGEST_SIZE; #ifndef NO_SKID XMEMCPY(current + added, list->subjectKeyIdHash,SIGNER_DIGEST_SIZE); added += SIGNER_DIGEST_SIZE; #endif list = list->next; } return added; } /* Persist cert cache to memory, have lock */ static WC_INLINE int DoMemSaveCertCache(WOLFSSL_CERT_MANAGER* cm, void* mem, int sz) { int realSz; int ret = WOLFSSL_SUCCESS; int i; WOLFSSL_ENTER("DoMemSaveCertCache"); realSz = GetCertCacheMemSize(cm); if (realSz > sz) { WOLFSSL_MSG("Mem output buffer too small"); ret = BUFFER_E; } else { byte* current; CertCacheHeader hdr; hdr.version = WOLFSSL_CACHE_CERT_VERSION; hdr.rows = CA_TABLE_SIZE; SetCertHeaderColumns(cm, hdr.columns); hdr.signerSz = (int)sizeof(Signer); XMEMCPY(mem, &hdr, sizeof(CertCacheHeader)); current = (byte*)mem + sizeof(CertCacheHeader); for (i = 0; i < CA_TABLE_SIZE; ++i) current += StoreCertRow(cm, current, i); } return ret; } #if !defined(NO_FILESYSTEM) /* Persist cert cache to file */ int CM_SaveCertCache(WOLFSSL_CERT_MANAGER* cm, const char* fname) { XFILE file; int rc = WOLFSSL_SUCCESS; int memSz; byte* mem; WOLFSSL_ENTER("CM_SaveCertCache"); file = XFOPEN(fname, "w+b"); if (file == XBADFILE) { WOLFSSL_MSG("Couldn't open cert cache save file"); return WOLFSSL_BAD_FILE; } if (wc_LockMutex(&cm->caLock) != 0) { WOLFSSL_MSG("wc_LockMutex on caLock failed"); XFCLOSE(file); return BAD_MUTEX_E; } memSz = GetCertCacheMemSize(cm); mem = (byte*)XMALLOC(memSz, cm->heap, DYNAMIC_TYPE_TMP_BUFFER); if (mem == NULL) { WOLFSSL_MSG("Alloc for tmp buffer failed"); rc = MEMORY_E; } else { rc = DoMemSaveCertCache(cm, mem, memSz); if (rc == WOLFSSL_SUCCESS) { int ret = (int)XFWRITE(mem, memSz, 1, file); if (ret != 1) { WOLFSSL_MSG("Cert cache file write failed"); rc = FWRITE_ERROR; } } XFREE(mem, cm->heap, DYNAMIC_TYPE_TMP_BUFFER); } wc_UnLockMutex(&cm->caLock); XFCLOSE(file); return rc; } /* Restore cert cache from file */ int CM_RestoreCertCache(WOLFSSL_CERT_MANAGER* cm, const char* fname) { XFILE file; int rc = WOLFSSL_SUCCESS; int ret; int memSz; byte* mem; WOLFSSL_ENTER("CM_RestoreCertCache"); file = XFOPEN(fname, "rb"); if (file == XBADFILE) { WOLFSSL_MSG("Couldn't open cert cache save file"); return WOLFSSL_BAD_FILE; } if(XFSEEK(file, 0, XSEEK_END) != 0) { XFCLOSE(file); return WOLFSSL_BAD_FILE; } memSz = (int)XFTELL(file); XREWIND(file); if (memSz > MAX_WOLFSSL_FILE_SIZE || memSz <= 0) { WOLFSSL_MSG("CM_RestoreCertCache file size error"); XFCLOSE(file); return WOLFSSL_BAD_FILE; } mem = (byte*)XMALLOC(memSz, cm->heap, DYNAMIC_TYPE_TMP_BUFFER); if (mem == NULL) { WOLFSSL_MSG("Alloc for tmp buffer failed"); XFCLOSE(file); return MEMORY_E; } ret = (int)XFREAD(mem, memSz, 1, file); if (ret != 1) { WOLFSSL_MSG("Cert file read error"); rc = FREAD_ERROR; } else { rc = CM_MemRestoreCertCache(cm, mem, memSz); if (rc != WOLFSSL_SUCCESS) { WOLFSSL_MSG("Mem restore cert cache failed"); } } XFREE(mem, cm->heap, DYNAMIC_TYPE_TMP_BUFFER); XFCLOSE(file); return rc; } #endif /* NO_FILESYSTEM */ /* Persist cert cache to memory */ int CM_MemSaveCertCache(WOLFSSL_CERT_MANAGER* cm, void* mem, int sz, int* used) { int ret = WOLFSSL_SUCCESS; WOLFSSL_ENTER("CM_MemSaveCertCache"); if (wc_LockMutex(&cm->caLock) != 0) { WOLFSSL_MSG("wc_LockMutex on caLock failed"); return BAD_MUTEX_E; } ret = DoMemSaveCertCache(cm, mem, sz); if (ret == WOLFSSL_SUCCESS) *used = GetCertCacheMemSize(cm); wc_UnLockMutex(&cm->caLock); return ret; } /* Restore cert cache from memory */ int CM_MemRestoreCertCache(WOLFSSL_CERT_MANAGER* cm, const void* mem, int sz) { int ret = WOLFSSL_SUCCESS; int i; CertCacheHeader* hdr = (CertCacheHeader*)mem; byte* current = (byte*)mem + sizeof(CertCacheHeader); byte* end = (byte*)mem + sz; /* don't go over */ WOLFSSL_ENTER("CM_MemRestoreCertCache"); if (current > end) { WOLFSSL_MSG("Cert Cache Memory buffer too small"); return BUFFER_E; } if (hdr->version != WOLFSSL_CACHE_CERT_VERSION || hdr->rows != CA_TABLE_SIZE || hdr->signerSz != (int)sizeof(Signer)) { WOLFSSL_MSG("Cert Cache Memory header mismatch"); return CACHE_MATCH_ERROR; } if (wc_LockMutex(&cm->caLock) != 0) { WOLFSSL_MSG("wc_LockMutex on caLock failed"); return BAD_MUTEX_E; } FreeSignerTable(cm->caTable, CA_TABLE_SIZE, cm->heap); for (i = 0; i < CA_TABLE_SIZE; ++i) { int added = RestoreCertRow(cm, current, i, hdr->columns[i], end); if (added < 0) { WOLFSSL_MSG("RestoreCertRow error"); ret = added; break; } current += added; } wc_UnLockMutex(&cm->caLock); return ret; } /* get how big the the cert cache save buffer needs to be */ int CM_GetCertCacheMemSize(WOLFSSL_CERT_MANAGER* cm) { int sz; WOLFSSL_ENTER("CM_GetCertCacheMemSize"); if (wc_LockMutex(&cm->caLock) != 0) { WOLFSSL_MSG("wc_LockMutex on caLock failed"); return BAD_MUTEX_E; } sz = GetCertCacheMemSize(cm); wc_UnLockMutex(&cm->caLock); return sz; } #endif /* PERSIST_CERT_CACHE */ #endif /* NO_CERTS */ #ifdef OPENSSL_EXTRA /* removes all cipher suites from the list that contain "toRemove" * returns the new list size on success */ static int wolfSSL_remove_ciphers(char* list, int sz, const char* toRemove) { int idx = 0; char* next = (char*)list; int totalSz = sz; if (list == NULL) { return 0; } do { char* current = next; char name[MAX_SUITE_NAME + 1]; word32 length; next = XSTRSTR(next, ":"); length = min(sizeof(name), !next ? (word32)XSTRLEN(current) /* last */ : (word32)(next - current)); XSTRNCPY(name, current, length); name[(length == sizeof(name)) ? length - 1 : length] = 0; if (XSTRSTR(name, toRemove)) { XMEMMOVE(list + idx, list + idx + length, totalSz - (idx + length)); totalSz -= length; list[totalSz] = '\0'; next = current; } else { idx += length; } } while (next++); /* ++ needed to skip ':' */ return totalSz; } /* * build enabled cipher list w/ TLS13 or w/o TLS13 suites * @param ctx a pointer to WOLFSSL_CTX structure * @param suites currently enabled suites * @param onlytlsv13suites flag whether correcting w/ TLS13 suites * or w/o TLS13 suties * @param list suites list that user wants to update * @return suites list on success, otherwise NULL */ static char* buildEnabledCipherList(WOLFSSL_CTX* ctx, Suites* suites, int tls13Only, const char* list) { word32 idx = 0; word32 listsz = 0; word32 len = 0; word32 ianasz = 0; const char* enabledcs = NULL; char* locallist = NULL; char* head = NULL; byte cipherSuite0; byte cipherSuite; /* sanity check */ if (ctx == NULL || suites == NULL || list == NULL) return NULL; if (!suites->setSuites) return NULL; listsz = (word32)XSTRLEN(list); /* calculate necessary buffer length */ for(idx = 0; idx < suites->suiteSz; idx++) { cipherSuite0 = suites->suites[idx]; cipherSuite = suites->suites[++idx]; if (tls13Only && cipherSuite0 == TLS13_BYTE) { enabledcs = GetCipherNameInternal(cipherSuite0, cipherSuite); } else if (!tls13Only && cipherSuite0 != TLS13_BYTE) { enabledcs = GetCipherNameInternal(cipherSuite0, cipherSuite); } else continue; if (XSTRCMP(enabledcs, "None") != 0) { len += (word32)XSTRLEN(enabledcs) + 2; } } len += listsz + 2; /* build string */ if (len > (listsz + 2)) { locallist = (char*)XMALLOC(len, ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); /* sanity check */ if (!locallist) return NULL; XMEMSET(locallist, 0, len); head = locallist; if (!tls13Only) { /* always tls13 suites in the head position */ XSTRNCPY(locallist, list, len); locallist += listsz; *locallist++ = ':'; *locallist = 0; len -= listsz + 1; } for(idx = 0; idx < suites->suiteSz; idx++) { cipherSuite0 = suites->suites[idx]; cipherSuite = suites->suites[++idx]; if (tls13Only && cipherSuite0 == TLS13_BYTE) { enabledcs = GetCipherNameInternal(cipherSuite0, cipherSuite); } else if (!tls13Only && cipherSuite0 != TLS13_BYTE) { enabledcs = GetCipherNameInternal(cipherSuite0, cipherSuite); } else continue; ianasz = (int)XSTRLEN(enabledcs); if (ianasz + 1 < len) { XSTRNCPY(locallist, enabledcs, len); locallist += ianasz; *locallist++ = ':'; *locallist = 0; len -= ianasz + 1; } else{ XFREE(locallist, ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); return NULL; } } if (tls13Only) { XSTRNCPY(locallist, list, len); locallist += listsz; *locallist = 0; } return head; } else return NULL; } /* * check if the list has TLS13 and pre-TLS13 suites * @param list cipher suite list that user want to set * @return mixed: 0, only pre-TLS13: 1, only TLS13: 2 */ static int CheckcipherList(const char* list) { int ret; int findTLSv13Suites = 0; int findbeforeSuites = 0; byte cipherSuite0; byte cipherSuite1; int flags; char* next = (char*)list; do { char* current = next; char name[MAX_SUITE_NAME + 1]; word32 length = MAX_SUITE_NAME; word32 current_length; next = XSTRSTR(next, ":"); current_length = (!next) ? (word32)XSTRLEN(current) : (word32)(next - current); if (current_length < length) { length = current_length; } XMEMCPY(name, current, length); name[length] = 0; ret = wolfSSL_get_cipher_suite_from_name(name, &cipherSuite0, &cipherSuite1, &flags); if (ret == 0) { if (cipherSuite0 == TLS13_BYTE) { /* TLSv13 suite */ findTLSv13Suites = 1; break; } else { findbeforeSuites = 1; break; } } if (findTLSv13Suites == 1 && findbeforeSuites == 1) { /* list has mixed suites */ return 0; } } while (next++); /* ++ needed to skip ':' */ if (findTLSv13Suites == 0 && findbeforeSuites == 1) { return 1;/* only before TLSv13 suites */ } else if (findTLSv13Suites == 1 && findbeforeSuites == 0) { return 2;/* only TLSv13 suties */ } else { return 0;/* handle as mixed */ } } /* parse some bulk lists like !eNULL / !aNULL * * returns WOLFSSL_SUCCESS on success and sets the cipher suite list */ static int wolfSSL_parse_cipher_list(WOLFSSL_CTX* ctx, Suites* suites, const char* list) { int ret = 0; const int suiteSz = GetCipherNamesSize(); char* next = (char*)list; const CipherSuiteInfo* names = GetCipherNames(); char* localList = NULL; int sz = 0; int listattribute = 0; char* buildcipherList = NULL; int tls13Only = 0; if (suites == NULL || list == NULL) { WOLFSSL_MSG("NULL argument"); return WOLFSSL_FAILURE; } /* does list contain eNULL or aNULL? */ if (XSTRSTR(list, "aNULL") || XSTRSTR(list, "eNULL")) { do { char* current = next; char name[MAX_SUITE_NAME + 1]; int i; word32 length = MAX_SUITE_NAME; word32 current_length; next = XSTRSTR(next, ":"); current_length = (!next) ? (word32)XSTRLEN(current) : (word32)(next - current); if (current_length < length) { length = current_length; } XMEMCPY(name, current, length); name[length] = 0; /* check for "not" case */ if (name[0] == '!' && suiteSz > 0) { /* populate list with all suites if not already created */ if (localList == NULL) { for (i = 0; i < suiteSz; i++) { sz += (int)XSTRLEN(names[i].name) + 2; } localList = (char*)XMALLOC(sz, ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); if (localList == NULL) { return WOLFSSL_FAILURE; } wolfSSL_get_ciphers(localList, sz); sz = (int)XSTRLEN(localList); } if (XSTRSTR(name, "eNULL")) { wolfSSL_remove_ciphers(localList, sz, "-NULL"); } } } while (next++); /* ++ needed to skip ':' */ ret = SetCipherList(ctx, suites, localList); XFREE(localList, ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); return (ret)? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; } else { listattribute = CheckcipherList(list); if (listattribute == 0) { /* list has mixed(pre-TLSv13 and TLSv13) suites * update cipher suites the same as before */ return (SetCipherList(ctx, suites, list)) ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; } else if (listattribute == 1) { /* list has only pre-TLSv13 suites. * Only update before TLSv13 suites. */ tls13Only = 1; } else if (listattribute == 2) { /* list has only TLSv13 suites. Only update TLv13 suites * simulate set_ciphersuites() compatibility layer API */ tls13Only = 0; } buildcipherList = buildEnabledCipherList(ctx, ctx->suites, tls13Only, list); if (buildcipherList) { ret = SetCipherList(ctx, suites, buildcipherList); XFREE(buildcipherList, ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); } else { ret = SetCipherList(ctx, suites, list); } return ret; } } #endif int wolfSSL_CTX_set_cipher_list(WOLFSSL_CTX* ctx, const char* list) { WOLFSSL_ENTER("wolfSSL_CTX_set_cipher_list"); if (ctx == NULL) return WOLFSSL_FAILURE; /* alloc/init on demand only */ if (ctx->suites == NULL) { ctx->suites = (Suites*)XMALLOC(sizeof(Suites), ctx->heap, DYNAMIC_TYPE_SUITES); if (ctx->suites == NULL) { WOLFSSL_MSG("Memory alloc for Suites failed"); return WOLFSSL_FAILURE; } XMEMSET(ctx->suites, 0, sizeof(Suites)); } #ifdef OPENSSL_EXTRA return wolfSSL_parse_cipher_list(ctx, ctx->suites, list); #else return (SetCipherList(ctx, ctx->suites, list)) ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; #endif } int wolfSSL_set_cipher_list(WOLFSSL* ssl, const char* list) { WOLFSSL_ENTER("wolfSSL_set_cipher_list"); #ifdef SINGLE_THREADED if (ssl->ctx->suites == ssl->suites) { ssl->suites = (Suites*)XMALLOC(sizeof(Suites), ssl->heap, DYNAMIC_TYPE_SUITES); if (ssl->suites == NULL) { WOLFSSL_MSG("Suites Memory error"); return MEMORY_E; } *ssl->suites = *ssl->ctx->suites; ssl->options.ownSuites = 1; } #endif #ifdef OPENSSL_EXTRA return wolfSSL_parse_cipher_list(ssl->ctx, ssl->suites, list); #else return (SetCipherList(ssl->ctx, ssl->suites, list)) ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; #endif } #ifdef HAVE_KEYING_MATERIAL #define TLS_PRF_LABEL_CLIENT_FINISHED "client finished" #define TLS_PRF_LABEL_SERVER_FINISHED "server finished" #define TLS_PRF_LABEL_MASTER_SECRET "master secret" #define TLS_PRF_LABEL_EXT_MASTER_SECRET "extended master secret" #define TLS_PRF_LABEL_KEY_EXPANSION "key expansion" static const struct ForbiddenLabels { const char* label; size_t labelLen; } forbiddenLabels[] = { {TLS_PRF_LABEL_CLIENT_FINISHED, XSTR_SIZEOF(TLS_PRF_LABEL_CLIENT_FINISHED)}, {TLS_PRF_LABEL_SERVER_FINISHED, XSTR_SIZEOF(TLS_PRF_LABEL_SERVER_FINISHED)}, {TLS_PRF_LABEL_MASTER_SECRET, XSTR_SIZEOF(TLS_PRF_LABEL_MASTER_SECRET)}, {TLS_PRF_LABEL_EXT_MASTER_SECRET, XSTR_SIZEOF(TLS_PRF_LABEL_EXT_MASTER_SECRET)}, {TLS_PRF_LABEL_KEY_EXPANSION, XSTR_SIZEOF(TLS_PRF_LABEL_KEY_EXPANSION)}, {NULL, 0}, }; /** * Implement RFC 5705 * TLS 1.3 uses a different exporter definition (section 7.5 of RFC 8446) * @return WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE on error */ int wolfSSL_export_keying_material(WOLFSSL *ssl, unsigned char *out, size_t outLen, const char *label, size_t labelLen, const unsigned char *context, size_t contextLen, int use_context) { byte* seed = NULL; word32 seedLen; const struct ForbiddenLabels* fl; WOLFSSL_ENTER("wolfSSL_export_keying_material"); if (ssl == NULL || out == NULL || label == NULL || (use_context && contextLen && context == NULL)) { WOLFSSL_MSG("Bad argument"); return WOLFSSL_FAILURE; } /* clientRandom + serverRandom * OR * clientRandom + serverRandom + ctx len encoding + ctx */ seedLen = !use_context ? (word32)SEED_LEN : (word32)SEED_LEN + 2 + (word32)contextLen; if (ssl->options.saveArrays == 0 || ssl->arrays == NULL) { WOLFSSL_MSG("To export keying material wolfSSL needs to keep handshake " "data. Call wolfSSL_KeepArrays before attempting to " "export keyid material."); return WOLFSSL_FAILURE; } /* check forbidden labels */ for (fl = &forbiddenLabels[0]; fl->label != NULL; fl++) { if (labelLen >= fl->labelLen && XMEMCMP(label, fl->label, fl->labelLen) == 0) { WOLFSSL_MSG("Forbidden label"); return WOLFSSL_FAILURE; } } #ifdef WOLFSSL_TLS13 if (IsAtLeastTLSv1_3(ssl->version)) { /* Path for TLS 1.3 */ if (!use_context) { contextLen = 0; context = (byte*)""; /* Give valid pointer for 0 length memcpy */ } if (Tls13_Exporter(ssl, out, (word32)outLen, label, labelLen, context, contextLen) != 0) { WOLFSSL_MSG("Tls13_Exporter error"); return WOLFSSL_FAILURE; } return WOLFSSL_SUCCESS; } #endif /* Path for <=TLS 1.2 */ seed = (byte*)XMALLOC(seedLen, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (seed == NULL) { WOLFSSL_MSG("malloc error"); return WOLFSSL_FAILURE; } XMEMCPY(seed, ssl->arrays->clientRandom, RAN_LEN); XMEMCPY(seed + RAN_LEN, ssl->arrays->serverRandom, RAN_LEN); if (use_context) { /* Encode len in big endian */ seed[SEED_LEN ] = (contextLen >> 8) & 0xFF; seed[SEED_LEN + 1] = (contextLen) & 0xFF; if (contextLen) { /* 0 length context is allowed */ XMEMCPY(seed + SEED_LEN + 2, context, contextLen); } } PRIVATE_KEY_UNLOCK(); if (wc_PRF_TLS(out, (word32)outLen, ssl->arrays->masterSecret, SECRET_LEN, (byte*)label, (word32)labelLen, seed, seedLen, IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm, ssl->heap, ssl->devId) != 0) { WOLFSSL_MSG("wc_PRF_TLS error"); PRIVATE_KEY_LOCK(); XFREE(seed, NULL, DYNAMIC_TYPE_TMP_BUFFER); return WOLFSSL_FAILURE; } PRIVATE_KEY_LOCK(); XFREE(seed, NULL, DYNAMIC_TYPE_TMP_BUFFER); return WOLFSSL_SUCCESS; } #endif /* HAVE_KEYING_MATERIAL */ int wolfSSL_dtls_get_using_nonblock(WOLFSSL* ssl) { int useNb = 0; if (ssl == NULL) return WOLFSSL_FAILURE; WOLFSSL_ENTER("wolfSSL_dtls_get_using_nonblock"); if (ssl->options.dtls) { #ifdef WOLFSSL_DTLS useNb = ssl->options.dtlsUseNonblock; #endif } else { WOLFSSL_MSG("wolfSSL_dtls_get_using_nonblock() is " "DEPRECATED for non-DTLS use."); } return useNb; } #ifndef WOLFSSL_LEANPSK void wolfSSL_dtls_set_using_nonblock(WOLFSSL* ssl, int nonblock) { (void)nonblock; WOLFSSL_ENTER("wolfSSL_dtls_set_using_nonblock"); if (ssl == NULL) return; if (ssl->options.dtls) { #ifdef WOLFSSL_DTLS ssl->options.dtlsUseNonblock = (nonblock != 0); #endif } else { WOLFSSL_MSG("wolfSSL_dtls_set_using_nonblock() is " "DEPRECATED for non-DTLS use."); } } #ifdef WOLFSSL_DTLS int wolfSSL_dtls_get_current_timeout(WOLFSSL* ssl) { int timeout = 0; if (ssl) timeout = ssl->dtls_timeout; WOLFSSL_LEAVE("wolfSSL_dtls_get_current_timeout()", timeout); return timeout; } #ifdef WOLFSSL_DTLS13 /* * This API returns 1 when the user should set a short timeout for receiving * data. It is recommended that it is at most 1/4 the value returned by * wolfSSL_dtls_get_current_timeout(). */ int wolfSSL_dtls13_use_quick_timeout(WOLFSSL* ssl) { return ssl->dtls13FastTimeout; } /* * When this is set, a DTLS 1.3 connection will send acks immediately when a * disruption is detected to shortcut timeouts. This results in potentially * more traffic but may make the handshake quicker. */ void wolfSSL_dtls13_set_send_more_acks(WOLFSSL* ssl, int value) { if (ssl != NULL) ssl->options.dtls13SendMoreAcks = !!value; } #endif /* WOLFSSL_DTLS13 */ int wolfSSL_DTLSv1_get_timeout(WOLFSSL* ssl, WOLFSSL_TIMEVAL* timeleft) { if (ssl && timeleft) { XMEMSET(timeleft, 0, sizeof(WOLFSSL_TIMEVAL)); timeleft->tv_sec = ssl->dtls_timeout; } return 0; } #ifndef NO_WOLFSSL_STUB int wolfSSL_DTLSv1_handle_timeout(WOLFSSL* ssl) { WOLFSSL_STUB("SSL_DTLSv1_handle_timeout"); (void)ssl; return 0; } #endif #ifndef NO_WOLFSSL_STUB void wolfSSL_DTLSv1_set_initial_timeout_duration(WOLFSSL* ssl, word32 duration_ms) { WOLFSSL_STUB("SSL_DTLSv1_set_initial_timeout_duration"); (void)ssl; (void)duration_ms; } #endif /* user may need to alter init dtls recv timeout, WOLFSSL_SUCCESS on ok */ int wolfSSL_dtls_set_timeout_init(WOLFSSL* ssl, int timeout) { if (ssl == NULL || timeout < 0) return BAD_FUNC_ARG; if (timeout > ssl->dtls_timeout_max) { WOLFSSL_MSG("Can't set dtls timeout init greater than dtls timeout max"); return BAD_FUNC_ARG; } ssl->dtls_timeout_init = timeout; ssl->dtls_timeout = timeout; return WOLFSSL_SUCCESS; } /* user may need to alter max dtls recv timeout, WOLFSSL_SUCCESS on ok */ int wolfSSL_dtls_set_timeout_max(WOLFSSL* ssl, int timeout) { if (ssl == NULL || timeout < 0) return BAD_FUNC_ARG; if (timeout < ssl->dtls_timeout_init) { WOLFSSL_MSG("Can't set dtls timeout max less than dtls timeout init"); return BAD_FUNC_ARG; } ssl->dtls_timeout_max = timeout; return WOLFSSL_SUCCESS; } int wolfSSL_dtls_got_timeout(WOLFSSL* ssl) { int result = WOLFSSL_SUCCESS; WOLFSSL_ENTER("wolfSSL_dtls_got_timeout()"); if (ssl == NULL) return WOLFSSL_FATAL_ERROR; #ifdef WOLFSSL_DTLS13 if (ssl->options.dtls && IsAtLeastTLSv1_3(ssl->version)) { result = Dtls13RtxTimeout(ssl); if (result < 0) { if (result == WANT_WRITE) ssl->dtls13SendingAckOrRtx = 1; ssl->error = result; WOLFSSL_ERROR(result); return WOLFSSL_FATAL_ERROR; } return WOLFSSL_SUCCESS; } #endif /* WOLFSSL_DTLS13 */ if ((IsSCR(ssl) || !ssl->options.handShakeDone)) { if (DtlsMsgPoolTimeout(ssl) < 0){ ssl->error = SOCKET_ERROR_E; WOLFSSL_ERROR(ssl->error); result = WOLFSSL_FATAL_ERROR; } else if ((result = DtlsMsgPoolSend(ssl, 0)) < 0) { ssl->error = result; WOLFSSL_ERROR(result); result = WOLFSSL_FATAL_ERROR; } else { /* Reset return value to success */ result = WOLFSSL_SUCCESS; } } WOLFSSL_LEAVE("wolfSSL_dtls_got_timeout()", result); return result; } /* retransmit all the saves messages, WOLFSSL_SUCCESS on ok */ int wolfSSL_dtls_retransmit(WOLFSSL* ssl) { WOLFSSL_ENTER("wolfSSL_dtls_retransmit()"); if (ssl == NULL) return WOLFSSL_FATAL_ERROR; if (!ssl->options.handShakeDone) { int result = DtlsMsgPoolSend(ssl, 0); if (result < 0) { ssl->error = result; WOLFSSL_ERROR(result); return WOLFSSL_FATAL_ERROR; } } return 0; } #endif /* DTLS */ #endif /* LEANPSK */ #if defined(WOLFSSL_DTLS) && !defined(NO_WOLFSSL_SERVER) /* Not an SSL function, return 0 for success, error code otherwise */ /* Prereq: ssl's RNG needs to be initialized. */ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, const byte* secret, word32 secretSz) { int ret = 0; WOLFSSL_ENTER("wolfSSL_DTLS_SetCookieSecret"); if (ssl == NULL) { WOLFSSL_MSG("need a SSL object"); return BAD_FUNC_ARG; } if (secret != NULL && secretSz == 0) { WOLFSSL_MSG("can't have a new secret without a size"); return BAD_FUNC_ARG; } /* If secretSz is 0, use the default size. */ if (secretSz == 0) secretSz = COOKIE_SECRET_SZ; if (secretSz != ssl->buffers.dtlsCookieSecret.length) { byte* newSecret; if (ssl->buffers.dtlsCookieSecret.buffer != NULL) { ForceZero(ssl->buffers.dtlsCookieSecret.buffer, ssl->buffers.dtlsCookieSecret.length); XFREE(ssl->buffers.dtlsCookieSecret.buffer, ssl->heap, DYNAMIC_TYPE_NONE); } newSecret = (byte*)XMALLOC(secretSz, ssl->heap,DYNAMIC_TYPE_COOKIE_PWD); if (newSecret == NULL) { ssl->buffers.dtlsCookieSecret.buffer = NULL; ssl->buffers.dtlsCookieSecret.length = 0; WOLFSSL_MSG("couldn't allocate new cookie secret"); return MEMORY_ERROR; } ssl->buffers.dtlsCookieSecret.buffer = newSecret; ssl->buffers.dtlsCookieSecret.length = secretSz; #ifdef WOLFSSL_CHECK_MEM_ZERO wc_MemZero_Add("wolfSSL_DTLS_SetCookieSecret secret", ssl->buffers.dtlsCookieSecret.buffer, ssl->buffers.dtlsCookieSecret.length); #endif } /* If the supplied secret is NULL, randomly generate a new secret. */ if (secret == NULL) { ret = wc_RNG_GenerateBlock(ssl->rng, ssl->buffers.dtlsCookieSecret.buffer, secretSz); } else XMEMCPY(ssl->buffers.dtlsCookieSecret.buffer, secret, secretSz); WOLFSSL_LEAVE("wolfSSL_DTLS_SetCookieSecret", 0); return ret; } #endif /* WOLFSSL_DTLS && !NO_WOLFSSL_SERVER */ /* EITHER SIDE METHODS */ #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE) WOLFSSL_METHOD* wolfSSLv23_method(void) { return wolfSSLv23_method_ex(NULL); } WOLFSSL_METHOD* wolfSSLv23_method_ex(void* heap) { WOLFSSL_METHOD* m = NULL; WOLFSSL_ENTER("SSLv23_method"); #if !defined(NO_WOLFSSL_CLIENT) m = wolfSSLv23_client_method_ex(heap); #elif !defined(NO_WOLFSSL_SERVER) m = wolfSSLv23_server_method_ex(heap); #else (void)heap; #endif if (m != NULL) { m->side = WOLFSSL_NEITHER_END; } return m; } #ifdef WOLFSSL_ALLOW_SSLV3 WOLFSSL_METHOD* wolfSSLv3_method(void) { return wolfSSLv3_method_ex(NULL); } WOLFSSL_METHOD* wolfSSLv3_method_ex(void* heap) { WOLFSSL_METHOD* m = NULL; WOLFSSL_ENTER("SSLv3_method"); #if !defined(NO_WOLFSSL_CLIENT) m = wolfSSLv3_client_method_ex(heap); #elif !defined(NO_WOLFSSL_SERVER) m = wolfSSLv3_server_method_ex(heap); #endif if (m != NULL) { m->side = WOLFSSL_NEITHER_END; } return m; } #endif #endif /* OPENSSL_EXTRA || WOLFSSL_EITHER_SIDE */ /* client only parts */ #ifndef NO_WOLFSSL_CLIENT #ifdef OPENSSL_EXTRA WOLFSSL_METHOD* wolfSSLv2_client_method(void) { WOLFSSL_STUB("wolfSSLv2_client_method"); return NULL; } #endif #if defined(WOLFSSL_ALLOW_SSLV3) && !defined(NO_OLD_TLS) WOLFSSL_METHOD* wolfSSLv3_client_method(void) { return wolfSSLv3_client_method_ex(NULL); } WOLFSSL_METHOD* wolfSSLv3_client_method_ex(void* heap) { WOLFSSL_METHOD* method = (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), heap, DYNAMIC_TYPE_METHOD); (void)heap; WOLFSSL_ENTER("SSLv3_client_method_ex"); if (method) InitSSL_Method(method, MakeSSLv3()); return method; } #endif /* WOLFSSL_ALLOW_SSLV3 && !NO_OLD_TLS */ WOLFSSL_METHOD* wolfSSLv23_client_method(void) { return wolfSSLv23_client_method_ex(NULL); } WOLFSSL_METHOD* wolfSSLv23_client_method_ex(void* heap) { WOLFSSL_METHOD* method = (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), heap, DYNAMIC_TYPE_METHOD); (void)heap; WOLFSSL_ENTER("SSLv23_client_method_ex"); if (method) { #if !defined(NO_SHA256) || defined(WOLFSSL_SHA384) || defined(WOLFSSL_SHA512) #if defined(WOLFSSL_TLS13) InitSSL_Method(method, MakeTLSv1_3()); #elif !defined(WOLFSSL_NO_TLS12) InitSSL_Method(method, MakeTLSv1_2()); #elif !defined(NO_OLD_TLS) InitSSL_Method(method, MakeTLSv1_1()); #endif #else #ifndef NO_OLD_TLS InitSSL_Method(method, MakeTLSv1_1()); #endif #endif #if !defined(NO_OLD_TLS) || defined(WOLFSSL_TLS13) method->downgrade = 1; #endif } return method; } /* please see note at top of README if you get an error from connect */ WOLFSSL_ABI int wolfSSL_connect(WOLFSSL* ssl) { #if !(defined(WOLFSSL_NO_TLS12) && defined(NO_OLD_TLS) && defined(WOLFSSL_TLS13)) int neededState; byte advanceState; #endif int ret = 0; (void)ret; WOLFSSL_ENTER("SSL_connect()"); #ifdef HAVE_ERRNO_H errno = 0; #endif if (ssl == NULL) return BAD_FUNC_ARG; #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE) if (ssl->options.side == WOLFSSL_NEITHER_END) { ssl->error = InitSSL_Side(ssl, WOLFSSL_CLIENT_END); if (ssl->error != WOLFSSL_SUCCESS) { WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } ssl->error = 0; /* expected to be zero here */ } #ifdef OPENSSL_EXTRA if (ssl->CBIS != NULL) { ssl->CBIS(ssl, SSL_ST_CONNECT, WOLFSSL_SUCCESS); ssl->cbmode = SSL_CB_WRITE; } #endif #endif /* OPENSSL_EXTRA || WOLFSSL_EITHER_SIDE */ #if defined(WOLFSSL_NO_TLS12) && defined(NO_OLD_TLS) && defined(WOLFSSL_TLS13) return wolfSSL_connect_TLSv13(ssl); #else #ifdef WOLFSSL_TLS13 if (ssl->options.tls1_3) return wolfSSL_connect_TLSv13(ssl); #endif #ifdef WOLFSSL_WOLFSENTRY_HOOKS if (ssl->ConnectFilter) { wolfSSL_netfilter_decision_t res; if ((ssl->ConnectFilter(ssl, ssl->ConnectFilter_arg, &res) == WOLFSSL_SUCCESS) && (res == WOLFSSL_NETFILTER_REJECT)) { ssl->error = SOCKET_FILTERED_E; WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } } #endif /* WOLFSSL_WOLFSENTRY_HOOKS */ if (ssl->options.side != WOLFSSL_CLIENT_END) { ssl->error = SIDE_ERROR; WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } #ifdef WOLFSSL_DTLS if (ssl->version.major == DTLS_MAJOR) { ssl->options.dtls = 1; ssl->options.tls = 1; ssl->options.tls1_1 = 1; } #endif /* fragOffset is non-zero when sending fragments. On the last * fragment, fragOffset is zero again, and the state can be * advanced. */ advanceState = ssl->fragOffset == 0 && (ssl->options.connectState == CONNECT_BEGIN || ssl->options.connectState == HELLO_AGAIN || (ssl->options.connectState >= FIRST_REPLY_DONE && ssl->options.connectState <= FIRST_REPLY_FOURTH)); ; #ifdef WOLFSSL_DTLS13 if (ssl->options.dtls && IsAtLeastTLSv1_3(ssl->version)) advanceState = advanceState && !ssl->dtls13SendingAckOrRtx; #endif /* WOLFSSL_DTLS13 */ if (ssl->buffers.outputBuffer.length > 0 #ifdef WOLFSSL_ASYNC_CRYPT /* do not send buffered or advance state if last error was an async pending operation */ && ssl->error != WC_PENDING_E #endif ) { ret = SendBuffered(ssl); if (ret == 0) { if (ssl->fragOffset == 0 && !ssl->options.buildingMsg) { if (advanceState) { ssl->options.connectState++; WOLFSSL_MSG("connect state: " "Advanced from last buffered fragment send"); } #ifdef WOLFSSL_ASYNC_IO /* Cleanup async */ FreeAsyncCtx(ssl, 0); #endif } else { WOLFSSL_MSG("connect state: " "Not advanced, more fragments to send"); } } else { ssl->error = ret; WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } } ret = RetrySendAlert(ssl); if (ret != 0) { ssl->error = ret; WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } switch (ssl->options.connectState) { case CONNECT_BEGIN : /* always send client hello first */ if ( (ssl->error = SendClientHello(ssl)) != 0) { WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } ssl->options.connectState = CLIENT_HELLO_SENT; WOLFSSL_MSG("connect state: CLIENT_HELLO_SENT"); FALL_THROUGH; case CLIENT_HELLO_SENT : neededState = ssl->options.resuming ? SERVER_FINISHED_COMPLETE : SERVER_HELLODONE_COMPLETE; #ifdef WOLFSSL_DTLS /* In DTLS, when resuming, we can go straight to FINISHED, * or do a cookie exchange and then skip to FINISHED, assume * we need the cookie exchange first. */ if (IsDtlsNotSctpMode(ssl)) neededState = SERVER_HELLOVERIFYREQUEST_COMPLETE; #endif /* get response */ while (ssl->options.serverState < neededState) { #ifdef WOLFSSL_TLS13 if (ssl->options.tls1_3) return wolfSSL_connect_TLSv13(ssl); #endif if ( (ssl->error = ProcessReply(ssl)) < 0) { WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } /* if resumption failed, reset needed state */ else if (neededState == SERVER_FINISHED_COMPLETE) if (!ssl->options.resuming) { #ifdef WOLFSSL_DTLS if (IsDtlsNotSctpMode(ssl)) neededState = SERVER_HELLOVERIFYREQUEST_COMPLETE; else #endif neededState = SERVER_HELLODONE_COMPLETE; } #ifdef WOLFSSL_DTLS13 if (ssl->options.dtls && IsAtLeastTLSv1_3(ssl->version) && ssl->dtls13Rtx.sendAcks == 1) { ssl->dtls13Rtx.sendAcks = 0; /* we aren't negotiated the version yet, so we aren't sure * the other end can speak v1.3. On the other side we have * received a unified records, assuming that the * ServerHello got lost, we will send an empty ACK. In case * the server is a DTLS with version less than 1.3, it * should just ignore the message */ if ((ssl->error = SendDtls13Ack(ssl)) < 0) { if (ssl->error == WANT_WRITE) ssl->dtls13SendingAckOrRtx = 1; WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } } #endif /* WOLFSSL_DTLS13 */ } ssl->options.connectState = HELLO_AGAIN; WOLFSSL_MSG("connect state: HELLO_AGAIN"); FALL_THROUGH; case HELLO_AGAIN : if (ssl->options.certOnly) return WOLFSSL_SUCCESS; #ifdef WOLFSSL_TLS13 if (ssl->options.tls1_3) return wolfSSL_connect_TLSv13(ssl); #endif #ifdef WOLFSSL_DTLS if (ssl->options.serverState == SERVER_HELLOVERIFYREQUEST_COMPLETE) { if (IsDtlsNotSctpMode(ssl)) { /* re-init hashes, exclude first hello and verify request */ if ((ssl->error = InitHandshakeHashes(ssl)) != 0) { WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } if ( (ssl->error = SendClientHello(ssl)) != 0) { WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } } } #endif ssl->options.connectState = HELLO_AGAIN_REPLY; WOLFSSL_MSG("connect state: HELLO_AGAIN_REPLY"); FALL_THROUGH; case HELLO_AGAIN_REPLY : #ifdef WOLFSSL_DTLS if (IsDtlsNotSctpMode(ssl)) { neededState = ssl->options.resuming ? SERVER_FINISHED_COMPLETE : SERVER_HELLODONE_COMPLETE; /* get response */ while (ssl->options.serverState < neededState) { if ( (ssl->error = ProcessReply(ssl)) < 0) { WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } /* if resumption failed, reset needed state */ if (neededState == SERVER_FINISHED_COMPLETE) { if (!ssl->options.resuming) neededState = SERVER_HELLODONE_COMPLETE; } } } #endif ssl->options.connectState = FIRST_REPLY_DONE; WOLFSSL_MSG("connect state: FIRST_REPLY_DONE"); FALL_THROUGH; case FIRST_REPLY_DONE : #if !defined(NO_CERTS) && !defined(WOLFSSL_NO_CLIENT_AUTH) #ifdef WOLFSSL_TLS13 if (ssl->options.tls1_3) return wolfSSL_connect_TLSv13(ssl); #endif if (ssl->options.sendVerify) { if ( (ssl->error = SendCertificate(ssl)) != 0) { #ifdef WOLFSSL_CHECK_ALERT_ON_ERR ProcessReplyEx(ssl, 1); /* See if an alert was sent. */ #endif WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } WOLFSSL_MSG("sent: certificate"); } #endif ssl->options.connectState = FIRST_REPLY_FIRST; WOLFSSL_MSG("connect state: FIRST_REPLY_FIRST"); FALL_THROUGH; case FIRST_REPLY_FIRST : #ifdef WOLFSSL_TLS13 if (ssl->options.tls1_3) return wolfSSL_connect_TLSv13(ssl); #endif if (!ssl->options.resuming) { if ( (ssl->error = SendClientKeyExchange(ssl)) != 0) { #ifdef WOLFSSL_CHECK_ALERT_ON_ERR ProcessReplyEx(ssl, 1); /* See if an alert was sent. */ #endif WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } WOLFSSL_MSG("sent: client key exchange"); } ssl->options.connectState = FIRST_REPLY_SECOND; WOLFSSL_MSG("connect state: FIRST_REPLY_SECOND"); FALL_THROUGH; #if !defined(WOLFSSL_NO_TLS12) || !defined(NO_OLD_TLS) case FIRST_REPLY_SECOND : /* CLIENT: Fail-safe for Server Authentication. */ if (!ssl->options.peerAuthGood) { WOLFSSL_MSG("Server authentication did not happen"); ssl->error = NO_PEER_VERIFY; return WOLFSSL_FATAL_ERROR; } #if !defined(NO_CERTS) && !defined(WOLFSSL_NO_CLIENT_AUTH) if (ssl->options.sendVerify) { if ( (ssl->error = SendCertificateVerify(ssl)) != 0) { #ifdef WOLFSSL_CHECK_ALERT_ON_ERR ProcessReplyEx(ssl, 1); /* See if an alert was sent. */ #endif WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } WOLFSSL_MSG("sent: certificate verify"); } #endif /* !NO_CERTS && !WOLFSSL_NO_CLIENT_AUTH */ ssl->options.connectState = FIRST_REPLY_THIRD; WOLFSSL_MSG("connect state: FIRST_REPLY_THIRD"); FALL_THROUGH; case FIRST_REPLY_THIRD : if ( (ssl->error = SendChangeCipher(ssl)) != 0) { #ifdef WOLFSSL_CHECK_ALERT_ON_ERR ProcessReplyEx(ssl, 1); /* See if an alert was sent. */ #endif WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } WOLFSSL_MSG("sent: change cipher spec"); ssl->options.connectState = FIRST_REPLY_FOURTH; WOLFSSL_MSG("connect state: FIRST_REPLY_FOURTH"); FALL_THROUGH; case FIRST_REPLY_FOURTH : if ( (ssl->error = SendFinished(ssl)) != 0) { #ifdef WOLFSSL_CHECK_ALERT_ON_ERR ProcessReplyEx(ssl, 1); /* See if an alert was sent. */ #endif WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } WOLFSSL_MSG("sent: finished"); ssl->options.connectState = FINISHED_DONE; WOLFSSL_MSG("connect state: FINISHED_DONE"); FALL_THROUGH; #ifdef WOLFSSL_DTLS13 case WAIT_FINISHED_ACK: ssl->options.connectState = FINISHED_DONE; FALL_THROUGH; #endif /* WOLFSSL_DTLS13 */ case FINISHED_DONE : /* get response */ while (ssl->options.serverState < SERVER_FINISHED_COMPLETE) if ( (ssl->error = ProcessReply(ssl)) < 0) { WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } ssl->options.connectState = SECOND_REPLY_DONE; WOLFSSL_MSG("connect state: SECOND_REPLY_DONE"); FALL_THROUGH; case SECOND_REPLY_DONE: #ifndef NO_HANDSHAKE_DONE_CB if (ssl->hsDoneCb) { int cbret = ssl->hsDoneCb(ssl, ssl->hsDoneCtx); if (cbret < 0) { ssl->error = cbret; WOLFSSL_MSG("HandShake Done Cb don't continue error"); return WOLFSSL_FATAL_ERROR; } } #endif /* NO_HANDSHAKE_DONE_CB */ if (!ssl->options.dtls) { if (!ssl->options.keepResources) { FreeHandshakeResources(ssl); } } #ifdef WOLFSSL_DTLS else { ssl->options.dtlsHsRetain = 1; } #endif /* WOLFSSL_DTLS */ #if defined(WOLFSSL_ASYNC_CRYPT) && defined(HAVE_SECURE_RENEGOTIATION) /* This may be necessary in async so that we don't try to * renegotiate again */ if (ssl->secure_renegotiation && ssl->secure_renegotiation->startScr) { ssl->secure_renegotiation->startScr = 0; } #endif /* WOLFSSL_ASYNC_CRYPT && HAVE_SECURE_RENEGOTIATION */ #if defined(WOLFSSL_ASYNC_IO) && !defined(WOLFSSL_ASYNC_CRYPT) /* Free the remaining async context if not using it for crypto */ FreeAsyncCtx(ssl, 1); #endif ssl->error = 0; /* clear the error */ WOLFSSL_LEAVE("SSL_connect()", WOLFSSL_SUCCESS); return WOLFSSL_SUCCESS; #endif /* !WOLFSSL_NO_TLS12 || !NO_OLD_TLS */ default: WOLFSSL_MSG("Unknown connect state ERROR"); return WOLFSSL_FATAL_ERROR; /* unknown connect state */ } #endif /* !WOLFSSL_NO_TLS12 || !NO_OLD_TLS || !WOLFSSL_TLS13 */ } #endif /* NO_WOLFSSL_CLIENT */ /* server only parts */ #ifndef NO_WOLFSSL_SERVER #ifdef OPENSSL_EXTRA WOLFSSL_METHOD* wolfSSLv2_server_method(void) { WOLFSSL_STUB("wolfSSLv2_server_method"); return 0; } #endif #if defined(WOLFSSL_ALLOW_SSLV3) && !defined(NO_OLD_TLS) WOLFSSL_METHOD* wolfSSLv3_server_method(void) { return wolfSSLv3_server_method_ex(NULL); } WOLFSSL_METHOD* wolfSSLv3_server_method_ex(void* heap) { WOLFSSL_METHOD* method = (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), heap, DYNAMIC_TYPE_METHOD); (void)heap; WOLFSSL_ENTER("SSLv3_server_method_ex"); if (method) { InitSSL_Method(method, MakeSSLv3()); method->side = WOLFSSL_SERVER_END; } return method; } #endif /* WOLFSSL_ALLOW_SSLV3 && !NO_OLD_TLS */ WOLFSSL_METHOD* wolfSSLv23_server_method(void) { return wolfSSLv23_server_method_ex(NULL); } WOLFSSL_METHOD* wolfSSLv23_server_method_ex(void* heap) { WOLFSSL_METHOD* method = (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), heap, DYNAMIC_TYPE_METHOD); (void)heap; WOLFSSL_ENTER("SSLv23_server_method_ex"); if (method) { #if !defined(NO_SHA256) || defined(WOLFSSL_SHA384) || defined(WOLFSSL_SHA512) #ifdef WOLFSSL_TLS13 InitSSL_Method(method, MakeTLSv1_3()); #elif !defined(WOLFSSL_NO_TLS12) InitSSL_Method(method, MakeTLSv1_2()); #elif !defined(NO_OLD_TLS) InitSSL_Method(method, MakeTLSv1_1()); #endif #else #ifndef NO_OLD_TLS InitSSL_Method(method, MakeTLSv1_1()); #else #error Must have SHA256, SHA384 or SHA512 enabled for TLS 1.2 #endif #endif #if !defined(NO_OLD_TLS) || defined(WOLFSSL_TLS13) method->downgrade = 1; #endif method->side = WOLFSSL_SERVER_END; } return method; } WOLFSSL_ABI int wolfSSL_accept(WOLFSSL* ssl) { #if !(defined(WOLFSSL_NO_TLS12) && defined(NO_OLD_TLS) && defined(WOLFSSL_TLS13)) word16 havePSK = 0; word16 haveAnon = 0; word16 haveMcast = 0; #endif int ret = 0; (void)ret; if (ssl == NULL) return WOLFSSL_FATAL_ERROR; #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE) if (ssl->options.side == WOLFSSL_NEITHER_END) { WOLFSSL_MSG("Setting WOLFSSL_SSL to be server side"); ssl->error = InitSSL_Side(ssl, WOLFSSL_SERVER_END); if (ssl->error != WOLFSSL_SUCCESS) { WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } ssl->error = 0; /* expected to be zero here */ } #endif /* OPENSSL_EXTRA || WOLFSSL_EITHER_SIDE */ #if defined(WOLFSSL_NO_TLS12) && defined(NO_OLD_TLS) && defined(WOLFSSL_TLS13) return wolfSSL_accept_TLSv13(ssl); #else #ifdef WOLFSSL_TLS13 if (ssl->options.tls1_3) return wolfSSL_accept_TLSv13(ssl); #endif WOLFSSL_ENTER("SSL_accept()"); #ifdef WOLFSSL_WOLFSENTRY_HOOKS if (ssl->AcceptFilter) { wolfSSL_netfilter_decision_t res; if ((ssl->AcceptFilter(ssl, ssl->AcceptFilter_arg, &res) == WOLFSSL_SUCCESS) && (res == WOLFSSL_NETFILTER_REJECT)) { ssl->error = SOCKET_FILTERED_E; WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } } #endif /* WOLFSSL_WOLFSENTRY_HOOKS */ #ifdef HAVE_ERRNO_H errno = 0; #endif #ifndef NO_PSK havePSK = ssl->options.havePSK; #endif (void)havePSK; #ifdef HAVE_ANON haveAnon = ssl->options.haveAnon; #endif (void)haveAnon; #ifdef WOLFSSL_MULTICAST haveMcast = ssl->options.haveMcast; #endif (void)haveMcast; if (ssl->options.side != WOLFSSL_SERVER_END) { ssl->error = SIDE_ERROR; WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } #ifndef NO_CERTS /* in case used set_accept_state after init */ if (!havePSK && !haveAnon && !haveMcast) { #ifdef OPENSSL_EXTRA if (ssl->ctx->certSetupCb != NULL) { WOLFSSL_MSG("CertSetupCb set. server cert and " "key not checked"); } else #endif { if (!ssl->buffers.certificate || !ssl->buffers.certificate->buffer) { WOLFSSL_MSG("accept error: server cert required"); ssl->error = NO_PRIVATE_KEY; WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } if (!ssl->buffers.key || !ssl->buffers.key->buffer) { /* allow no private key if using existing key */ #ifdef WOLF_PRIVATE_KEY_ID if (ssl->devId != INVALID_DEVID #ifdef HAVE_PK_CALLBACKS || wolfSSL_CTX_IsPrivatePkSet(ssl->ctx) #endif ) { WOLFSSL_MSG("Allowing no server private key " "(external)"); } else #endif { WOLFSSL_MSG("accept error: server key required"); ssl->error = NO_PRIVATE_KEY; WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } } } } #endif #ifdef WOLFSSL_DTLS if (ssl->version.major == DTLS_MAJOR) { ssl->options.dtls = 1; ssl->options.tls = 1; ssl->options.tls1_1 = 1; } #endif if (ssl->buffers.outputBuffer.length > 0 #ifdef WOLFSSL_ASYNC_CRYPT /* do not send buffered or advance state if last error was an async pending operation */ && ssl->error != WC_PENDING_E #endif ) { ret = SendBuffered(ssl); if (ret == 0) { /* fragOffset is non-zero when sending fragments. On the last * fragment, fragOffset is zero again, and the state can be * advanced. */ if (ssl->fragOffset == 0 && !ssl->options.buildingMsg) { if (ssl->options.acceptState == ACCEPT_FIRST_REPLY_DONE || ssl->options.acceptState == SERVER_HELLO_SENT || ssl->options.acceptState == CERT_SENT || ssl->options.acceptState == CERT_STATUS_SENT || ssl->options.acceptState == KEY_EXCHANGE_SENT || ssl->options.acceptState == CERT_REQ_SENT || ssl->options.acceptState == ACCEPT_SECOND_REPLY_DONE || ssl->options.acceptState == TICKET_SENT || ssl->options.acceptState == CHANGE_CIPHER_SENT) { ssl->options.acceptState++; WOLFSSL_MSG("accept state: " "Advanced from last buffered fragment send"); } #ifdef WOLFSSL_ASYNC_IO /* Cleanup async */ FreeAsyncCtx(ssl, 0); #endif } else { WOLFSSL_MSG("accept state: " "Not advanced, more fragments to send"); } } else { ssl->error = ret; WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } } ret = RetrySendAlert(ssl); if (ret != 0) { ssl->error = ret; WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } switch (ssl->options.acceptState) { case ACCEPT_BEGIN : #ifdef HAVE_SECURE_RENEGOTIATION case ACCEPT_BEGIN_RENEG: #endif /* get response */ while (ssl->options.clientState < CLIENT_HELLO_COMPLETE) if ( (ssl->error = ProcessReply(ssl)) < 0) { WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } #ifdef WOLFSSL_TLS13 ssl->options.acceptState = ACCEPT_CLIENT_HELLO_DONE; WOLFSSL_MSG("accept state ACCEPT_CLIENT_HELLO_DONE"); FALL_THROUGH; case ACCEPT_CLIENT_HELLO_DONE : if (ssl->options.tls1_3) { return wolfSSL_accept_TLSv13(ssl); } #endif #ifdef WOLFSSL_DTLS if (ssl->chGoodCb != NULL && !IsSCR(ssl)) { int cbret = ssl->chGoodCb(ssl, ssl->chGoodCtx); if (cbret < 0) { ssl->error = cbret; WOLFSSL_MSG("ClientHello Good Cb don't continue error"); return WOLFSSL_FATAL_ERROR; } } #endif ssl->options.acceptState = ACCEPT_FIRST_REPLY_DONE; WOLFSSL_MSG("accept state ACCEPT_FIRST_REPLY_DONE"); FALL_THROUGH; case ACCEPT_FIRST_REPLY_DONE : if ( (ssl->error = SendServerHello(ssl)) != 0) { WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } ssl->options.acceptState = SERVER_HELLO_SENT; WOLFSSL_MSG("accept state SERVER_HELLO_SENT"); FALL_THROUGH; case SERVER_HELLO_SENT : #ifdef WOLFSSL_TLS13 if (ssl->options.tls1_3) { return wolfSSL_accept_TLSv13(ssl); } #endif #ifndef NO_CERTS if (!ssl->options.resuming) if ( (ssl->error = SendCertificate(ssl)) != 0) { WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } #endif ssl->options.acceptState = CERT_SENT; WOLFSSL_MSG("accept state CERT_SENT"); FALL_THROUGH; case CERT_SENT : #ifndef NO_CERTS if (!ssl->options.resuming) if ( (ssl->error = SendCertificateStatus(ssl)) != 0) { WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } #endif ssl->options.acceptState = CERT_STATUS_SENT; WOLFSSL_MSG("accept state CERT_STATUS_SENT"); FALL_THROUGH; case CERT_STATUS_SENT : #ifdef WOLFSSL_TLS13 if (ssl->options.tls1_3) { return wolfSSL_accept_TLSv13(ssl); } #endif if (!ssl->options.resuming) if ( (ssl->error = SendServerKeyExchange(ssl)) != 0) { WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } ssl->options.acceptState = KEY_EXCHANGE_SENT; WOLFSSL_MSG("accept state KEY_EXCHANGE_SENT"); FALL_THROUGH; case KEY_EXCHANGE_SENT : #ifndef NO_CERTS if (!ssl->options.resuming) { if (ssl->options.verifyPeer) { if ( (ssl->error = SendCertificateRequest(ssl)) != 0) { WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } } else { /* SERVER: Peer auth good if not verifying client. */ ssl->options.peerAuthGood = 1; } } #endif ssl->options.acceptState = CERT_REQ_SENT; WOLFSSL_MSG("accept state CERT_REQ_SENT"); FALL_THROUGH; case CERT_REQ_SENT : if (!ssl->options.resuming) if ( (ssl->error = SendServerHelloDone(ssl)) != 0) { WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } ssl->options.acceptState = SERVER_HELLO_DONE; WOLFSSL_MSG("accept state SERVER_HELLO_DONE"); FALL_THROUGH; case SERVER_HELLO_DONE : if (!ssl->options.resuming) { while (ssl->options.clientState < CLIENT_FINISHED_COMPLETE) if ( (ssl->error = ProcessReply(ssl)) < 0) { WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } } ssl->options.acceptState = ACCEPT_SECOND_REPLY_DONE; WOLFSSL_MSG("accept state ACCEPT_SECOND_REPLY_DONE"); FALL_THROUGH; case ACCEPT_SECOND_REPLY_DONE : #ifndef NO_CERTS /* SERVER: When not resuming and verifying peer but no certificate * received and not failing when not received then peer auth good. */ if (!ssl->options.resuming && ssl->options.verifyPeer && !ssl->options.havePeerCert && !ssl->options.failNoCert) { ssl->options.peerAuthGood = 1; } #endif /* !NO_CERTS */ #ifdef WOLFSSL_NO_CLIENT_AUTH if (!ssl->options.resuming) { ssl->options.peerAuthGood = 1; } #endif #ifdef HAVE_SESSION_TICKET if (ssl->options.createTicket && !ssl->options.noTicketTls12) { if ( (ssl->error = SendTicket(ssl)) != 0) { WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } } #endif /* HAVE_SESSION_TICKET */ ssl->options.acceptState = TICKET_SENT; WOLFSSL_MSG("accept state TICKET_SENT"); FALL_THROUGH; case TICKET_SENT: /* SERVER: Fail-safe for CLient Authentication. */ if (!ssl->options.peerAuthGood) { WOLFSSL_MSG("Client authentication did not happen"); return WOLFSSL_FATAL_ERROR; } if ( (ssl->error = SendChangeCipher(ssl)) != 0) { WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } ssl->options.acceptState = CHANGE_CIPHER_SENT; WOLFSSL_MSG("accept state CHANGE_CIPHER_SENT"); FALL_THROUGH; case CHANGE_CIPHER_SENT : if ( (ssl->error = SendFinished(ssl)) != 0) { WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } ssl->options.acceptState = ACCEPT_FINISHED_DONE; WOLFSSL_MSG("accept state ACCEPT_FINISHED_DONE"); FALL_THROUGH; case ACCEPT_FINISHED_DONE : if (ssl->options.resuming) while (ssl->options.clientState < CLIENT_FINISHED_COMPLETE) if ( (ssl->error = ProcessReply(ssl)) < 0) { WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } ssl->options.acceptState = ACCEPT_THIRD_REPLY_DONE; WOLFSSL_MSG("accept state ACCEPT_THIRD_REPLY_DONE"); FALL_THROUGH; case ACCEPT_THIRD_REPLY_DONE : #ifndef NO_HANDSHAKE_DONE_CB if (ssl->hsDoneCb) { int cbret = ssl->hsDoneCb(ssl, ssl->hsDoneCtx); if (cbret < 0) { ssl->error = cbret; WOLFSSL_MSG("HandShake Done Cb don't continue error"); return WOLFSSL_FATAL_ERROR; } } #endif /* NO_HANDSHAKE_DONE_CB */ if (!ssl->options.dtls) { if (!ssl->options.keepResources) { FreeHandshakeResources(ssl); } } #ifdef WOLFSSL_DTLS else { ssl->options.dtlsHsRetain = 1; } #endif /* WOLFSSL_DTLS */ #if defined(WOLFSSL_ASYNC_CRYPT) && defined(HAVE_SECURE_RENEGOTIATION) /* This may be necessary in async so that we don't try to * renegotiate again */ if (ssl->secure_renegotiation && ssl->secure_renegotiation->startScr) { ssl->secure_renegotiation->startScr = 0; } #endif /* WOLFSSL_ASYNC_CRYPT && HAVE_SECURE_RENEGOTIATION */ #if defined(WOLFSSL_ASYNC_IO) && !defined(WOLFSSL_ASYNC_CRYPT) /* Free the remaining async context if not using it for crypto */ FreeAsyncCtx(ssl, 1); #endif #if defined(WOLFSSL_SESSION_EXPORT) && defined(WOLFSSL_DTLS) if (ssl->dtls_export) { if ((ssl->error = wolfSSL_send_session(ssl)) != 0) { WOLFSSL_MSG("Export DTLS session error"); WOLFSSL_ERROR(ssl->error); return WOLFSSL_FATAL_ERROR; } } #endif ssl->error = 0; /* clear the error */ WOLFSSL_LEAVE("SSL_accept()", WOLFSSL_SUCCESS); return WOLFSSL_SUCCESS; default : WOLFSSL_MSG("Unknown accept state ERROR"); return WOLFSSL_FATAL_ERROR; } #endif /* !WOLFSSL_NO_TLS12 */ } #endif /* NO_WOLFSSL_SERVER */ #if defined(WOLFSSL_DTLS) && !defined(NO_WOLFSSL_SERVER) int wolfDTLS_SetChGoodCb(WOLFSSL* ssl, ClientHelloGoodCb cb, void* user_ctx) { WOLFSSL_ENTER("wolfDTLS_SetChGoodCb"); if (ssl == NULL) return BAD_FUNC_ARG; ssl->chGoodCb = cb; ssl->chGoodCtx = user_ctx; return WOLFSSL_SUCCESS; } #endif #ifndef NO_HANDSHAKE_DONE_CB int wolfSSL_SetHsDoneCb(WOLFSSL* ssl, HandShakeDoneCb cb, void* user_ctx) { WOLFSSL_ENTER("wolfSSL_SetHsDoneCb"); if (ssl == NULL) return BAD_FUNC_ARG; ssl->hsDoneCb = cb; ssl->hsDoneCtx = user_ctx; return WOLFSSL_SUCCESS; } #endif /* NO_HANDSHAKE_DONE_CB */ WOLFSSL_ABI int wolfSSL_Cleanup(void) { int ret = WOLFSSL_SUCCESS; /* Only the first error will be returned */ int release = 0; #if !defined(NO_SESSION_CACHE) && defined(ENABLE_SESSION_CACHE_ROW_LOCK) int i; #endif WOLFSSL_ENTER("wolfSSL_Cleanup"); if (initRefCount == 0) return ret; /* possibly no init yet, but not failure either way */ if ((count_mutex_valid == 1) && (wc_LockMutex(&count_mutex) != 0)) { WOLFSSL_MSG("Bad Lock Mutex count"); ret = BAD_MUTEX_E; } release = initRefCount-- == 1; if (initRefCount < 0) initRefCount = 0; if (count_mutex_valid == 1) { wc_UnLockMutex(&count_mutex); } if (!release) return ret; #ifdef OPENSSL_EXTRA if (bn_one) { wolfSSL_BN_free(bn_one); bn_one = NULL; } #endif #ifndef NO_SESSION_CACHE #ifdef ENABLE_SESSION_CACHE_ROW_LOCK for (i = 0; i < SESSION_ROWS; ++i) { if ((SessionCache[i].mutex_valid == 1) && (wc_FreeMutex(&SessionCache[i].row_mutex) != 0)) { if (ret == WOLFSSL_SUCCESS) ret = BAD_MUTEX_E; } SessionCache[i].mutex_valid = 0; } #else if ((session_mutex_valid == 1) && (wc_FreeMutex(&session_mutex) != 0)) { if (ret == WOLFSSL_SUCCESS) ret = BAD_MUTEX_E; } session_mutex_valid = 0; #endif #ifndef NO_CLIENT_CACHE if ((clisession_mutex_valid == 1) && (wc_FreeMutex(&clisession_mutex) != 0)) { if (ret == WOLFSSL_SUCCESS) ret = BAD_MUTEX_E; } clisession_mutex_valid = 0; #endif #endif /* !NO_SESSION_CACHE */ if ((count_mutex_valid == 1) && (wc_FreeMutex(&count_mutex) != 0)) { if (ret == WOLFSSL_SUCCESS) ret = BAD_MUTEX_E; } count_mutex_valid = 0; #ifdef OPENSSL_EXTRA wolfSSL_RAND_Cleanup(); #endif if (wolfCrypt_Cleanup() != 0) { WOLFSSL_MSG("Error with wolfCrypt_Cleanup call"); if (ret == WOLFSSL_SUCCESS) ret = WC_CLEANUP_E; } #if FIPS_VERSION_GE(5,1) if (wolfCrypt_SetPrivateKeyReadEnable_fips(0, WC_KEYTYPE_ALL) < 0) { if (ret == WOLFSSL_SUCCESS) ret = WC_CLEANUP_E; } #endif #ifdef HAVE_GLOBAL_RNG if ((globalRNGMutex_valid == 1) && (wc_FreeMutex(&globalRNGMutex) != 0)) { if (ret == WOLFSSL_SUCCESS) ret = BAD_MUTEX_E; } globalRNGMutex_valid = 0; #if defined(OPENSSL_EXTRA) && defined(HAVE_HASHDRBG) wolfSSL_FIPS_drbg_free(gDrbgDefCtx); gDrbgDefCtx = NULL; #endif #endif return ret; } #ifndef NO_SESSION_CACHE /* some session IDs aren't random after all, let's make them random */ static WC_INLINE word32 HashSession(const byte* sessionID, word32 len, int* error) { byte digest[WC_MAX_DIGEST_SIZE]; #ifndef NO_MD5 *error = wc_Md5Hash(sessionID, len, digest); #elif !defined(NO_SHA) *error = wc_ShaHash(sessionID, len, digest); #elif !defined(NO_SHA256) *error = wc_Sha256Hash(sessionID, len, digest); #else #error "We need a digest to hash the session IDs" #endif return *error == 0 ? MakeWordFromHash(digest) : 0; /* 0 on failure */ } WOLFSSL_ABI void wolfSSL_flush_sessions(WOLFSSL_CTX* ctx, long tm) { /* static table now, no flushing needed */ (void)ctx; (void)tm; } /* set ssl session timeout in seconds */ WOLFSSL_ABI int wolfSSL_set_timeout(WOLFSSL* ssl, unsigned int to) { if (ssl == NULL) return BAD_FUNC_ARG; if (to == 0) to = WOLFSSL_SESSION_TIMEOUT; ssl->timeout = to; return WOLFSSL_SUCCESS; } /** * Sets ctx session timeout in seconds. * The timeout value set here should be reflected in the * "session ticket lifetime hint" if this API works in the openssl compat-layer. * Therefore wolfSSL_CTX_set_TicketHint is called internally. * Arguments: * - ctx WOLFSSL_CTX object which the timeout is set to * - to timeout value in second * Returns: * WOLFSSL_SUCCESS on success, BAD_FUNC_ARG on failure. * When WOLFSSL_ERROR_CODE_OPENSSL is defined, returns previous timeout value * on success, BAD_FUNC_ARG on failure. */ WOLFSSL_ABI int wolfSSL_CTX_set_timeout(WOLFSSL_CTX* ctx, unsigned int to) { #if defined(WOLFSSL_ERROR_CODE_OPENSSL) word32 prev_timeout = 0; #endif int ret = WOLFSSL_SUCCESS; (void)ret; if (ctx == NULL) ret = BAD_FUNC_ARG; if (ret == WOLFSSL_SUCCESS) { #if defined(WOLFSSL_ERROR_CODE_OPENSSL) prev_timeout = ctx->timeout; #endif if (to == 0) { ctx->timeout = WOLFSSL_SESSION_TIMEOUT; } else { ctx->timeout = to; } } #if defined(OPENSSL_EXTRA) && defined(HAVE_SESSION_TICKET) && \ !defined(NO_WOLFSSL_SERVER) if (ret == WOLFSSL_SUCCESS) { if (to == 0) { ret = wolfSSL_CTX_set_TicketHint(ctx, SESSION_TICKET_HINT_DEFAULT); } else { ret = wolfSSL_CTX_set_TicketHint(ctx, to); } } #endif /* OPENSSL_EXTRA && HAVE_SESSION_TICKET && !NO_WOLFSSL_SERVER */ #if defined(WOLFSSL_ERROR_CODE_OPENSSL) if (ret == WOLFSSL_SUCCESS) { return prev_timeout; } else { return ret; } #else return ret; #endif /* WOLFSSL_ERROR_CODE_OPENSSL */ } #ifndef NO_CLIENT_CACHE /* Get Session from Client cache based on id/len, return NULL on failure */ WOLFSSL_SESSION* wolfSSL_GetSessionClient(WOLFSSL* ssl, const byte* id, int len) { WOLFSSL_SESSION* ret = NULL; word32 row; int idx; int count; int error = 0; ClientSession* clSess; WOLFSSL_ENTER("GetSessionClient"); if (ssl->ctx->sessionCacheOff) { WOLFSSL_MSG("Session Cache off"); return NULL; } if (ssl->options.side == WOLFSSL_SERVER_END) return NULL; len = min(SERVER_ID_LEN, (word32)len); #ifdef HAVE_EXT_CACHE if (ssl->ctx->get_sess_cb != NULL) { int copy = 0; WOLFSSL_MSG("Calling external session cache"); ret = ssl->ctx->get_sess_cb(ssl, (byte*)id, len, ©); if (ret != NULL) { WOLFSSL_MSG("Session found in external cache"); return ret; } WOLFSSL_MSG("Session not found in external cache"); } if (ssl->ctx->internalCacheLookupOff) { WOLFSSL_MSG("Internal cache turned off"); return NULL; } #endif row = HashSession(id, len, &error) % CLIENT_SESSION_ROWS; if (error != 0) { WOLFSSL_MSG("Hash session failed"); return NULL; } if (wc_LockMutex(&clisession_mutex) != 0) { WOLFSSL_MSG("Client cache mutex lock failed"); return NULL; } /* start from most recently used */ count = min((word32)ClientCache[row].totalCount, CLIENT_SESSIONS_PER_ROW); idx = ClientCache[row].nextIdx - 1; if (idx < 0 || idx >= CLIENT_SESSIONS_PER_ROW) { idx = CLIENT_SESSIONS_PER_ROW - 1; /* if back to front, the previous was end */ } clSess = ClientCache[row].Clients; for (; count > 0; --count) { WOLFSSL_SESSION* current; SessionRow* sessRow; if (clSess[idx].serverRow >= SESSION_ROWS) { WOLFSSL_MSG("Client cache serverRow invalid"); break; } /* lock row */ sessRow = &SessionCache[clSess[idx].serverRow]; if (SESSION_ROW_LOCK(sessRow) != 0) { WOLFSSL_MSG("Session cache row lock failure"); break; } current = &sessRow->Sessions[clSess[idx].serverIdx]; if (XMEMCMP(current->serverID, id, len) == 0) { WOLFSSL_MSG("Found a serverid match for client"); if (LowResTimer() < (current->bornOn + current->timeout)) { WOLFSSL_MSG("Session valid"); ret = current; SESSION_ROW_UNLOCK(sessRow); break; } else { WOLFSSL_MSG("Session timed out"); /* could have more for id */ } } else { WOLFSSL_MSG("ServerID not a match from client table"); } SESSION_ROW_UNLOCK(sessRow); idx = idx > 0 ? idx - 1 : CLIENT_SESSIONS_PER_ROW - 1; } wc_UnLockMutex(&clisession_mutex); return ret; } #endif /* !NO_CLIENT_CACHE */ static int SslSessionCacheOff(const WOLFSSL* ssl, const WOLFSSL_SESSION* session) { (void)session; return ssl->options.sessionCacheOff #if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_FORCE_CACHE_ON_TICKET) && session->ticketLen == 0 #endif #ifdef OPENSSL_EXTRA && ssl->options.side != WOLFSSL_CLIENT_END #endif ; } int wolfSSL_GetSessionFromCache(WOLFSSL* ssl, WOLFSSL_SESSION* output) { WOLFSSL_SESSION* sess = NULL; const byte* id = NULL; word32 row; int idx; int count; int error = 0; SessionRow* sessRow; #ifdef HAVE_SESSION_TICKET #ifndef WOLFSSL_SMALL_STACK byte tmpTicket[PREALLOC_SESSION_TICKET_LEN]; #else byte* tmpTicket = NULL; #endif byte tmpBufSet = 0; #endif #if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) WOLFSSL_X509* peer = NULL; #endif byte bogusID[ID_LEN]; byte bogusIDSz = 0; WOLFSSL_ENTER("wolfSSL_GetSessionFromCache"); if (output == NULL) { WOLFSSL_MSG("NULL output"); return WOLFSSL_FAILURE; } if (SslSessionCacheOff(ssl, ssl->session)) return WOLFSSL_FAILURE; if (ssl->options.haveSessionId == 0) return WOLFSSL_FAILURE; #ifdef HAVE_SESSION_TICKET if (ssl->options.side == WOLFSSL_SERVER_END && ssl->options.useTicket == 1) return WOLFSSL_FAILURE; #endif XMEMSET(bogusID, 0, sizeof(bogusID)); if (!IsAtLeastTLSv1_3(ssl->version) && ssl->arrays != NULL) id = ssl->arrays->sessionID; else if (ssl->session->haveAltSessionID) { id = ssl->session->altSessionID; /* We want to restore the bogus ID for TLS compatibility */ if (output == ssl->session) { XMEMCPY(bogusID, ssl->session->sessionID, ID_LEN); bogusIDSz = ssl->session->sessionIDSz; } } else id = ssl->session->sessionID; #ifdef HAVE_EXT_CACHE if (ssl->ctx->get_sess_cb != NULL) { int copy = 0; /* Attempt to retrieve the session from the external cache. */ WOLFSSL_MSG("Calling external session cache"); sess = ssl->ctx->get_sess_cb(ssl, (byte*)id, ID_LEN, ©); if (sess != NULL) { WOLFSSL_MSG("Session found in external cache"); error = wolfSSL_DupSession(sess, output, 0); #ifdef HAVE_EX_DATA output->ownExData = 0; /* Session cache owns external data */ #endif /* If copy not set then free immediately */ if (!copy) wolfSSL_FreeSession(ssl->ctx, sess); /* We want to restore the bogus ID for TLS compatibility */ if (ssl->session->haveAltSessionID && output == ssl->session) { XMEMCPY(ssl->session->sessionID, bogusID, ID_LEN); ssl->session->sessionIDSz = bogusIDSz; } return error; } WOLFSSL_MSG("Session not found in external cache"); } if (ssl->ctx->internalCacheLookupOff) { WOLFSSL_MSG("Internal cache lookup turned off"); return WOLFSSL_FAILURE; } #endif row = HashSession(id, ID_LEN, &error) % SESSION_ROWS; if (error != 0) { WOLFSSL_MSG("Hash session failed"); return WOLFSSL_FAILURE; } #ifdef HAVE_SESSION_TICKET if (output->ticket == NULL || output->ticketLenAlloc < PREALLOC_SESSION_TICKET_LEN) { #ifdef WOLFSSL_SMALL_STACK tmpTicket = (byte*)XMALLOC(PREALLOC_SESSION_TICKET_LEN, output->heap, DYNAMIC_TYPE_TMP_BUFFER); if (tmpTicket == NULL) { WOLFSSL_MSG("tmpTicket malloc failed"); return WOLFSSL_FAILURE; } #endif if (output->ticketLenAlloc) XFREE(output->ticket, output->heap, DYNAMIC_TYPE_SESSION_TICK); output->ticket = tmpTicket; output->ticketLenAlloc = PREALLOC_SESSION_TICKET_LEN; output->ticketLen = 0; tmpBufSet = 1; } #endif #if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) if (output->peer != NULL) { wolfSSL_X509_free(output->peer); output->peer = NULL; } #endif /* lock row */ sessRow = &SessionCache[row]; if (SESSION_ROW_LOCK(sessRow) != 0) { WOLFSSL_MSG("Session cache row lock failure"); #ifdef HAVE_SESSION_TICKET if (tmpBufSet) { output->ticket = output->_staticTicket; output->ticketLenAlloc = 0; } #ifdef WOLFSSL_SMALL_STACK if (tmpTicket != NULL) XFREE(tmpTicket, output->heap, DYNAMIC_TYPE_TMP_BUFFER); #endif #endif return WOLFSSL_FAILURE; } /* start from most recently used */ count = min((word32)sessRow->totalCount, SESSIONS_PER_ROW); idx = sessRow->nextIdx - 1; if (idx < 0 || idx >= SESSIONS_PER_ROW) { idx = SESSIONS_PER_ROW - 1; /* if back to front, the previous was end */ } for (; count > 0; --count) { WOLFSSL_SESSION* current; current = &sessRow->Sessions[idx]; if (XMEMCMP(current->sessionID, id, ID_LEN) == 0 && current->side == ssl->options.side) { WOLFSSL_MSG("Found a session match"); if (LowResTimer() < (current->bornOn + current->timeout)) { WOLFSSL_MSG("Session valid"); sess = current; } else { WOLFSSL_MSG("Session timed out"); } break; /* no more sessionIDs whether valid or not that match */ } else { WOLFSSL_MSG("SessionID not a match at this idx"); } idx = idx > 0 ? idx - 1 : SESSIONS_PER_ROW - 1; } if (sess != NULL) { #if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) /* We don't want the peer member. We will free it at the end. */ if (sess->peer != NULL) { peer = sess->peer; sess->peer = NULL; } #endif error = wolfSSL_DupSession(sess, output, 1); #ifdef HAVE_EX_DATA output->ownExData = 0; /* Session cache owns external data */ #endif } else { error = WOLFSSL_FAILURE; } SESSION_ROW_UNLOCK(sessRow); /* We want to restore the bogus ID for TLS compatibility */ if (ssl->session->haveAltSessionID && output == ssl->session) { XMEMCPY(ssl->session->sessionID, bogusID, ID_LEN); ssl->session->sessionIDSz = bogusIDSz; } #ifdef HAVE_SESSION_TICKET if (tmpBufSet) { if (error == WOLFSSL_SUCCESS) { if (output->ticketLen > SESSION_TICKET_LEN) { output->ticket = (byte*)XMALLOC(output->ticketLen, output->heap, DYNAMIC_TYPE_SESSION_TICK); if (output->ticket == NULL) { error = WOLFSSL_FAILURE; output->ticket = output->_staticTicket; output->ticketLenAlloc = 0; output->ticketLen = 0; } } else { output->ticket = output->_staticTicket; output->ticketLenAlloc = 0; } } else { output->ticket = output->_staticTicket; output->ticketLenAlloc = 0; output->ticketLen = 0; } if (error == WOLFSSL_SUCCESS) { XMEMCPY(output->ticket, tmpTicket, output->ticketLen); } } #ifdef WOLFSSL_SMALL_STACK if (tmpTicket != NULL) XFREE(tmpTicket, output->heap, DYNAMIC_TYPE_TMP_BUFFER); #endif #endif #if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) if (peer != NULL) { wolfSSL_X509_free(peer); } #endif return error; } WOLFSSL_SESSION* wolfSSL_GetSession(WOLFSSL* ssl, byte* masterSecret, byte restoreSessionCerts) { WOLFSSL_SESSION* ret = NULL; (void)restoreSessionCerts; /* Kept for compatibility */ if (wolfSSL_GetSessionFromCache(ssl, ssl->session) == WOLFSSL_SUCCESS) { ret = ssl->session; } else { WOLFSSL_MSG("wolfSSL_GetSessionFromCache did not return a session"); } if (ret != NULL && masterSecret != NULL) XMEMCPY(masterSecret, ret->masterSecret, SECRET_LEN); return ret; } int wolfSSL_SetSession(WOLFSSL* ssl, WOLFSSL_SESSION* session) { SessionRow* sessRow = NULL; int ret = WOLFSSL_SUCCESS; session = ClientSessionToSession(session); if (ssl == NULL || session == NULL) { return WOLFSSL_FAILURE; } if (session->type == WOLFSSL_SESSION_TYPE_CACHE) { if (session->cacheRow < SESSION_ROWS) { sessRow = &SessionCache[session->cacheRow]; if (SESSION_ROW_LOCK(sessRow) != 0) { WOLFSSL_MSG("Session row lock failed"); return WOLFSSL_FAILURE; } } } if (ret == WOLFSSL_SUCCESS && SslSessionCacheOff(ssl, session)) { WOLFSSL_MSG("Session cache off"); ret = WOLFSSL_FAILURE; } if (ret == WOLFSSL_SUCCESS && ssl->options.side != WOLFSSL_NEITHER_END && (byte)ssl->options.side != session->side) { WOLFSSL_MSG("Setting session for wrong role"); ret = WOLFSSL_FAILURE; } if (ret == WOLFSSL_SUCCESS && wolfSSL_DupSession(session, ssl->session, 0) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("Session duplicate failed"); ret = WOLFSSL_FAILURE; } /* Let's copy over the altSessionID for local cache purposes */ if (ret == WOLFSSL_SUCCESS && session->haveAltSessionID) { ssl->session->haveAltSessionID = 1; XMEMCPY(ssl->session->altSessionID, session->altSessionID, ID_LEN); } if (sessRow != NULL) { SESSION_ROW_UNLOCK(sessRow); sessRow = NULL; } /* Note: the `session` variable cannot be used below, since the row is * un-locked */ if (ret != WOLFSSL_SUCCESS) return ret; #ifdef OPENSSL_EXTRA /* check for application context id */ if (ssl->sessionCtxSz > 0) { if (XMEMCMP(ssl->sessionCtx, ssl->session->sessionCtx, ssl->sessionCtxSz)) { /* context id did not match! */ WOLFSSL_MSG("Session context did not match"); return WOLFSSL_FAILURE; } } #endif /* OPENSSL_EXTRA */ if (LowResTimer() < (ssl->session->bornOn + ssl->session->timeout)) { ssl->options.resuming = 1; ssl->options.haveEMS = ssl->session->haveEMS; #if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \ defined(HAVE_SESSION_TICKET)) ssl->version = ssl->session->version; if (IsAtLeastTLSv1_3(ssl->version)) ssl->options.tls1_3 = 1; #endif #if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \ (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) ssl->options.cipherSuite0 = ssl->session->cipherSuite0; ssl->options.cipherSuite = ssl->session->cipherSuite; #endif #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) ssl->peerVerifyRet = (unsigned long)ssl->session->peerVerifyRet; #endif ret = WOLFSSL_SUCCESS; } else { #if defined(OPENSSL_EXTRA) && defined(WOLFSSL_ERROR_CODE_OPENSSL) WOLFSSL_MSG("Session is expired but return success for \ OpenSSL compatibility"); ret = WOLFSSL_SUCCESS; #else ret = WOLFSSL_FAILURE; /* session timed out */ #endif /* OPENSSL_EXTRA && WOLFSSL_ERROR_CODE_OPENSSL */ } return ret; } #ifdef WOLFSSL_SESSION_STATS static int get_locked_session_stats(word32* active, word32* total, word32* peak); #endif #ifndef NO_CLIENT_CACHE ClientSession* AddSessionToClientCache(int side, int row, int idx, byte* serverID, word16 idLen, const byte* sessionID, word16 useTicket) { int error = -1; word32 clientRow = 0, clientIdx = 0, sessionIDHash = 0; (void)useTicket; if (side == WOLFSSL_CLIENT_END && row != INVALID_SESSION_ROW && (idLen #ifdef HAVE_SESSION_TICKET || useTicket == 1 #endif || serverID != NULL )) { WOLFSSL_MSG("Trying to add client cache entry"); if (idLen) { clientRow = HashSession(serverID, idLen, &error) % CLIENT_SESSION_ROWS; } else if (serverID != NULL) { clientRow = HashSession(sessionID, ID_LEN, &error) % CLIENT_SESSION_ROWS; } else { error = -1; } if (error == 0 && wc_LockMutex(&clisession_mutex) == 0) { clientIdx = ClientCache[clientRow].nextIdx; if (clientIdx < CLIENT_SESSIONS_PER_ROW) { ClientCache[clientRow].Clients[clientIdx].serverRow = (word16)row; ClientCache[clientRow].Clients[clientIdx].serverIdx = (word16)idx; if (sessionID != NULL) { sessionIDHash = HashSession(sessionID, ID_LEN, &error); if (error == 0) { ClientCache[clientRow].Clients[clientIdx].sessionIDHash = sessionIDHash; } } } else { error = -1; ClientCache[clientRow].nextIdx = 0; /* reset index as saftey */ WOLFSSL_MSG("Invalid client cache index! " "Possible corrupted memory"); } if (error == 0) { WOLFSSL_MSG("Adding client cache entry"); if (ClientCache[clientRow].totalCount < CLIENT_SESSIONS_PER_ROW) ClientCache[clientRow].totalCount++; ClientCache[clientRow].nextIdx++; ClientCache[clientRow].nextIdx %= CLIENT_SESSIONS_PER_ROW; } wc_UnLockMutex(&clisession_mutex); } else { WOLFSSL_MSG("Hash session or lock failed"); error = -1; } } else { WOLFSSL_MSG("Skipping client cache"); } if (error == 0) return &ClientCache[clientRow].Clients[clientIdx]; else return NULL; } #endif /** * For backwards compatibility, this API needs to be used in *ALL* functions * that access the WOLFSSL_SESSION members directly. * * This API checks if the passed in session is actually a ClientSession object * and returns the matching session cache object. Otherwise just return the * input. ClientSession objects only occur in the ClientCache. They are not * allocated anywhere else. */ WOLFSSL_SESSION* ClientSessionToSession(const WOLFSSL_SESSION* session) { WOLFSSL_ENTER("ClientSessionToSession"); #ifdef NO_SESSION_CACHE_REF return (WOLFSSL_SESSION*)session; #else #ifndef NO_CLIENT_CACHE if (session == NULL) return NULL; /* Check if session points into ClientCache */ if ((byte*)session >= (byte*)ClientCache && /* Cast to byte* to make pointer arithmetic work per byte */ (byte*)session < ((byte*)ClientCache) + sizeof(ClientCache)) { ClientSession* clientSession = (ClientSession*)session; SessionRow* sessRow = NULL; WOLFSSL_SESSION* cacheSession = NULL; word32 sessionIDHash = 0; int error = 0; session = NULL; /* Default to NULL for failure case */ if (wc_LockMutex(&clisession_mutex) != 0) { WOLFSSL_MSG("Client cache mutex lock failed"); return NULL; } if (clientSession->serverRow >= SESSION_ROWS || clientSession->serverIdx >= SESSIONS_PER_ROW) { WOLFSSL_MSG("Client cache serverRow or serverIdx invalid"); error = -1; } if (error == 0) { /* Lock row */ sessRow = &SessionCache[clientSession->serverRow]; error = SESSION_ROW_LOCK(sessRow); if (error != 0) { WOLFSSL_MSG("Session cache row lock failure"); sessRow = NULL; } } if (error == 0) { cacheSession = &sessRow->Sessions[clientSession->serverIdx]; if (cacheSession->sessionIDSz == 0) { cacheSession = NULL; WOLFSSL_MSG("Session cache entry not set"); error = -1; } } if (error == 0) { /* Calculate the hash of the session ID */ sessionIDHash = HashSession(cacheSession->sessionID, ID_LEN, &error); } if (error == 0) { /* Check the session ID hash matches */ error = clientSession->sessionIDHash != sessionIDHash; } if (error == 0) { /* Hashes match */ session = cacheSession; WOLFSSL_MSG("Found session cache matching client session object"); } if (sessRow != NULL) { SESSION_ROW_UNLOCK(sessRow); } wc_UnLockMutex(&clisession_mutex); return (WOLFSSL_SESSION*)session; } else { /* Plain WOLFSSL_SESSION object */ return (WOLFSSL_SESSION*)session; } #else return (WOLFSSL_SESSION*)session; #endif #endif } int AddSessionToCache(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* addSession, const byte* id, byte idSz, int* sessionIndex, int side, word16 useTicket, ClientSession** clientCacheEntry) { WOLFSSL_SESSION* cacheSession = NULL; SessionRow* sessRow = NULL; word32 idx = 0; #if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) WOLFSSL_X509* peer = NULL; #endif #ifdef HAVE_SESSION_TICKET byte* cacheTicBuff = NULL; byte ticBuffUsed = 0; byte* ticBuff = NULL; int ticLen = 0; #endif int ret = 0; int row; int i; int overwrite = 0; (void)ctx; (void)sessionIndex; (void)useTicket; (void)clientCacheEntry; addSession = ClientSessionToSession(addSession); if (addSession == NULL || idSz == 0) { WOLFSSL_MSG("addSession NULL or idSz == 0"); return BAD_FUNC_ARG; } /* Find a position for the new session in cache and use that */ #ifdef HAVE_SESSION_TICKET ticLen = addSession->ticketLen; /* Alloc Memory here to avoid syscalls during lock */ if (ticLen > SESSION_TICKET_LEN) { ticBuff = (byte*)XMALLOC(ticLen, NULL, DYNAMIC_TYPE_SESSION_TICK); if (ticBuff == NULL) { return MEMORY_E; } } #endif /* Use the session object in the cache for external cache if required */ row = (int)(HashSession(id, ID_LEN, &ret) % SESSION_ROWS); if (ret != 0) { WOLFSSL_MSG("Hash session failed"); #ifdef HAVE_SESSION_TICKET XFREE(ticBuff, NULL, DYNAMIC_TYPE_SESSION_TICK); #endif return ret; } sessRow = &SessionCache[row]; if (SESSION_ROW_LOCK(sessRow) != 0) { #ifdef HAVE_SESSION_TICKET XFREE(ticBuff, NULL, DYNAMIC_TYPE_SESSION_TICK); #endif WOLFSSL_MSG("Session row lock failed"); return BAD_MUTEX_E; } for (i = 0; i < SESSIONS_PER_ROW && i < sessRow->totalCount; i++) { if (XMEMCMP(id, sessRow->Sessions[i].sessionID, ID_LEN) == 0 && sessRow->Sessions[i].side == side) { WOLFSSL_MSG("Session already exists. Overwriting."); overwrite = 1; idx = i; break; } } if (!overwrite) idx = sessRow->nextIdx; #ifdef SESSION_INDEX if (sessionIndex != NULL) *sessionIndex = (row << SESSIDX_ROW_SHIFT) | idx; #endif cacheSession = &sessRow->Sessions[idx]; #ifdef HAVE_EX_DATA if (cacheSession->rem_sess_cb && cacheSession->ownExData) { cacheSession->rem_sess_cb(NULL, cacheSession); /* Make sure not to call remove functions again */ cacheSession->ownExData = 0; cacheSession->rem_sess_cb = NULL; } #endif cacheSession->type = WOLFSSL_SESSION_TYPE_CACHE; cacheSession->cacheRow = row; #if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) /* Save the peer field to free after unlocking the row */ if (cacheSession->peer != NULL) peer = cacheSession->peer; cacheSession->peer = NULL; #endif #ifdef HAVE_SESSION_TICKET /* If we can re-use the existing buffer in cacheSession then we won't touch * ticBuff at all making it a very cheap malloc/free. The page on a modern * OS will most likely not even be allocated to the process. */ if (ticBuff != NULL && cacheSession->ticketLenAlloc < ticLen) { cacheTicBuff = cacheSession->ticket; ticBuffUsed = 1; cacheSession->ticket = ticBuff; cacheSession->ticketLenAlloc = (word16) ticLen; } #endif #ifdef SESSION_CERTS if (overwrite && addSession->chain.count == 0 && cacheSession->chain.count > 0) { /* Copy in the certs from the session */ addSession->chain.count = cacheSession->chain.count; XMEMCPY(addSession->chain.certs, cacheSession->chain.certs, sizeof(x509_buffer) * cacheSession->chain.count); } #endif /* SESSION_CERTS */ cacheSession->heap = NULL; /* Copy data into the cache object */ ret = wolfSSL_DupSession(addSession, cacheSession, 1) == WOLFSSL_FAILURE; if (ret == 0) { /* Increment the totalCount and the nextIdx */ if (sessRow->totalCount < SESSIONS_PER_ROW) sessRow->totalCount++; sessRow->nextIdx = (sessRow->nextIdx + 1) % SESSIONS_PER_ROW; if (id != addSession->sessionID) { /* ssl->session->sessionID may contain the bogus ID or we want the * ID from the arrays object */ XMEMCPY(cacheSession->sessionID, id, ID_LEN); cacheSession->sessionIDSz = ID_LEN; } #ifdef HAVE_EX_DATA if (ctx->rem_sess_cb != NULL) { addSession->ownExData = 0; cacheSession->ownExData = 1; cacheSession->rem_sess_cb = ctx->rem_sess_cb; } #endif } #ifdef HAVE_SESSION_TICKET else if (ticBuffUsed) { /* Error occured. Need to clean up the ticket buffer. */ cacheSession->ticket = cacheSession->_staticTicket; cacheSession->ticketLenAlloc = 0; cacheSession->ticketLen = 0; } #endif SESSION_ROW_UNLOCK(sessRow); cacheSession = NULL; /* Can't access after unlocked */ #ifndef NO_CLIENT_CACHE if (ret == 0 && clientCacheEntry != NULL) { ClientSession* clientCache = AddSessionToClientCache(side, row, idx, addSession->serverID, addSession->idLen, id, useTicket); if (clientCache != NULL) *clientCacheEntry = clientCache; } #endif #ifdef HAVE_SESSION_TICKET if (ticBuff != NULL && !ticBuffUsed) XFREE(ticBuff, NULL, DYNAMIC_TYPE_SESSION_TICK); if (cacheTicBuff != NULL) XFREE(cacheTicBuff, NULL, DYNAMIC_TYPE_SESSION_TICK); #endif #if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) if (peer != NULL) { wolfSSL_X509_free(peer); peer = NULL; /* Make sure not use after this point */ } #endif return ret; } #ifndef NO_CLIENT_CACHE #endif void AddSession(WOLFSSL* ssl) { int error = 0; const byte* id = NULL; byte idSz = 0; WOLFSSL_SESSION* session = ssl->session; #ifdef HAVE_EXT_CACHE int cbRet = 0; #endif (void)error; WOLFSSL_ENTER("AddSession"); if (SslSessionCacheOff(ssl, session)) { WOLFSSL_MSG("Cache off"); return; } if (ssl->options.haveSessionId == 0) { WOLFSSL_MSG("Don't have session id"); return; } #if defined(HAVE_SESSION_TICKET) && !defined(OPENSSL_EXTRA) /* For the compat layer generate a session object to use */ if (ssl->options.side == WOLFSSL_SERVER_END && ssl->options.useTicket == 1) { WOLFSSL_MSG("Using tickets instead of cache"); return; } #endif if (session->haveAltSessionID) { id = session->altSessionID; idSz = ID_LEN; } else { if (!IsAtLeastTLSv1_3(ssl->version) && ssl->arrays != NULL) { /* Make sure the session ID is available when the user calls any * get_session API */ XMEMCPY(session->sessionID, ssl->arrays->sessionID, ID_LEN); session->sessionIDSz = ssl->arrays->sessionIDSz; } id = session->sessionID; idSz = session->sessionIDSz; } session->timeout = ssl->timeout; session->side = (byte)ssl->options.side; if (!IsAtLeastTLSv1_3(ssl->version) && ssl->arrays != NULL) XMEMCPY(session->masterSecret, ssl->arrays->masterSecret, SECRET_LEN); session->haveEMS = ssl->options.haveEMS; #ifdef OPENSSL_EXTRA /* If using compatibility layer then check for and copy over session context * id. */ if (ssl->sessionCtxSz > 0 && ssl->sessionCtxSz < ID_LEN) { XMEMCPY(ssl->session->sessionCtx, ssl->sessionCtx, ssl->sessionCtxSz); session->sessionCtxSz = ssl->sessionCtxSz; } #endif session->timeout = ssl->timeout; session->bornOn = LowResTimer(); #if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \ defined(HAVE_SESSION_TICKET)) session->version = ssl->version; #endif #if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \ (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) session->cipherSuite0 = ssl->options.cipherSuite0; session->cipherSuite = ssl->options.cipherSuite; #endif #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) session->peerVerifyRet = (byte)ssl->peerVerifyRet; #endif /* Do this last so that if it fails, the rest of the session is setup. Do * this only for the client because if the server doesn't have an ID at * this point, it won't on resumption. */ if (idSz == 0 && ssl->options.side == WOLFSSL_CLIENT_END) { WC_RNG* rng = NULL; if (ssl->rng != NULL) rng = ssl->rng; #if defined(HAVE_GLOBAL_RNG) && defined(OPENSSL_EXTRA) else if (initGlobalRNG == 1 || wolfSSL_RAND_Init() == WOLFSSL_SUCCESS) { rng = &globalRNG; } #endif if (wc_RNG_GenerateBlock(rng, ssl->session->altSessionID, ID_LEN) != 0) return; ssl->session->haveAltSessionID = 1; id = ssl->session->altSessionID; idSz = ID_LEN; } /* Setup done */ if (ssl->options.side == WOLFSSL_SERVER_END /* No point in adding a * client session */ #ifdef HAVE_EXT_CACHE && !ssl->options.internalCacheOff #endif ) { /* Try to add the session to cache. Its ok if we don't succeed. */ (void)AddSessionToCache(ssl->ctx, session, id, idSz, #ifdef SESSION_INDEX &ssl->sessionIndex, #else NULL, #endif ssl->options.side, #ifdef HAVE_SESSION_TICKET ssl->options.useTicket, #else 0, #endif NULL ); } #ifdef HAVE_EXT_CACHE if (error == 0 && ssl->ctx->new_sess_cb != NULL) { wolfSSL_SESSION_up_ref(session); cbRet = ssl->ctx->new_sess_cb(ssl, session); if (cbRet == 0) wolfSSL_FreeSession(ssl->ctx, session); } #endif #if defined(WOLFSSL_SESSION_STATS) && defined(WOLFSSL_PEAK_SESSIONS) if (error == 0) { word32 active = 0; error = get_locked_session_stats(&active, NULL, NULL); if (error == WOLFSSL_SUCCESS) { error = 0; /* back to this function ok */ if (PeakSessions < active) { PeakSessions = active; } } } #endif /* WOLFSSL_SESSION_STATS && WOLFSSL_PEAK_SESSIONS */ (void)error; } #ifdef SESSION_INDEX int wolfSSL_GetSessionIndex(WOLFSSL* ssl) { WOLFSSL_ENTER("wolfSSL_GetSessionIndex"); WOLFSSL_LEAVE("wolfSSL_GetSessionIndex", ssl->sessionIndex); return ssl->sessionIndex; } int wolfSSL_GetSessionAtIndex(int idx, WOLFSSL_SESSION* session) { int row, col, result = WOLFSSL_FAILURE; SessionRow* sessRow; WOLFSSL_ENTER("wolfSSL_GetSessionAtIndex"); session = ClientSessionToSession(session); row = idx >> SESSIDX_ROW_SHIFT; col = idx & SESSIDX_IDX_MASK; if (session == NULL || row < 0 || row >= SESSION_ROWS || col >= SESSIONS_PER_ROW) { return WOLFSSL_FAILURE; } sessRow = &SessionCache[row]; if (SESSION_ROW_LOCK(sessRow) != 0) { return BAD_MUTEX_E; } XMEMCPY(session, &sessRow->Sessions[col], sizeof(WOLFSSL_SESSION)); result = WOLFSSL_SUCCESS; SESSION_ROW_UNLOCK(sessRow); WOLFSSL_LEAVE("wolfSSL_GetSessionAtIndex", result); return result; } #endif /* SESSION_INDEX */ #if defined(SESSION_CERTS) WOLFSSL_X509_CHAIN* wolfSSL_SESSION_get_peer_chain(WOLFSSL_SESSION* session) { WOLFSSL_X509_CHAIN* chain = NULL; WOLFSSL_ENTER("wolfSSL_SESSION_get_peer_chain"); session = ClientSessionToSession(session); if (session) chain = &session->chain; WOLFSSL_LEAVE("wolfSSL_SESSION_get_peer_chain", chain ? 1 : 0); return chain; } #ifdef OPENSSL_EXTRA /* gets the peer certificate associated with the session passed in * returns null on failure, the caller should not free the returned pointer */ WOLFSSL_X509* wolfSSL_SESSION_get0_peer(WOLFSSL_SESSION* session) { WOLFSSL_ENTER("wolfSSL_SESSION_get_peer_chain"); session = ClientSessionToSession(session); if (session) { int count; count = wolfSSL_get_chain_count(&session->chain); if (count < 1 || count >= MAX_CHAIN_DEPTH) { WOLFSSL_MSG("bad count found"); return NULL; } if (session->peer == NULL) { session->peer = wolfSSL_get_chain_X509(&session->chain, 0); } return session->peer; } WOLFSSL_MSG("No session passed in"); return NULL; } #endif /* OPENSSL_EXTRA */ #endif /* SESSION_INDEX && SESSION_CERTS */ #ifdef WOLFSSL_SESSION_STATS static int get_locked_session_stats(word32* active, word32* total, word32* peak) { int result = WOLFSSL_SUCCESS; int i; int count; int idx; word32 now = 0; word32 seen = 0; word32 ticks = LowResTimer(); WOLFSSL_ENTER("get_locked_session_stats"); #ifndef ENABLE_SESSION_CACHE_ROW_LOCK wc_LockMutex(&session_mutex); #endif for (i = 0; i < SESSION_ROWS; i++) { SessionRow* row = &SessionCache[i]; #ifdef ENABLE_SESSION_CACHE_ROW_LOCK if (SESSION_ROW_LOCK(row) != 0) { WOLFSSL_MSG("Session row cache mutex lock failed"); return BAD_MUTEX_E; } #endif seen += row->totalCount; if (active == NULL) { SESSION_ROW_UNLOCK(row); continue; } count = min((word32)row->totalCount, SESSIONS_PER_ROW); idx = row->nextIdx - 1; if (idx < 0 || idx >= SESSIONS_PER_ROW) { idx = SESSIONS_PER_ROW - 1; /* if back to front previous was end */ } for (; count > 0; --count) { /* if not expired then good */ if (ticks < (row->Sessions[idx].bornOn + row->Sessions[idx].timeout) ) { now++; } idx = idx > 0 ? idx - 1 : SESSIONS_PER_ROW - 1; } #ifdef ENABLE_SESSION_CACHE_ROW_LOCK SESSION_ROW_UNLOCK(row); #endif } #ifndef ENABLE_SESSION_CACHE_ROW_LOCK wc_UnLockMutex(&session_mutex); #endif if (active) { *active = now; } if (total) { *total = seen; } #ifdef WOLFSSL_PEAK_SESSIONS if (peak) { *peak = PeakSessions; } #else (void)peak; #endif WOLFSSL_LEAVE("get_locked_session_stats", result); return result; } /* return WOLFSSL_SUCCESS on ok */ int wolfSSL_get_session_stats(word32* active, word32* total, word32* peak, word32* maxSessions) { int result = WOLFSSL_SUCCESS; WOLFSSL_ENTER("wolfSSL_get_session_stats"); if (maxSessions) { *maxSessions = SESSIONS_PER_ROW * SESSION_ROWS; if (active == NULL && total == NULL && peak == NULL) return result; /* we're done */ } /* user must provide at least one query value */ if (active == NULL && total == NULL && peak == NULL) { return BAD_FUNC_ARG; } result = get_locked_session_stats(active, total, peak); WOLFSSL_LEAVE("wolfSSL_get_session_stats", result); return result; } #endif /* WOLFSSL_SESSION_STATS */ #ifdef PRINT_SESSION_STATS /* WOLFSSL_SUCCESS on ok */ int wolfSSL_PrintSessionStats(void) { word32 totalSessionsSeen = 0; word32 totalSessionsNow = 0; word32 peak = 0; word32 maxSessions = 0; int i; int ret; double E; /* expected freq */ double chiSquare = 0; ret = wolfSSL_get_session_stats(&totalSessionsNow, &totalSessionsSeen, &peak, &maxSessions); if (ret != WOLFSSL_SUCCESS) return ret; printf("Total Sessions Seen = %u\n", totalSessionsSeen); printf("Total Sessions Now = %u\n", totalSessionsNow); #ifdef WOLFSSL_PEAK_SESSIONS printf("Peak Sessions = %u\n", peak); #endif printf("Max Sessions = %u\n", maxSessions); E = (double)totalSessionsSeen / SESSION_ROWS; for (i = 0; i < SESSION_ROWS; i++) { double diff = SessionCache[i].totalCount - E; diff *= diff; /* square */ diff /= E; /* normalize */ chiSquare += diff; } printf(" chi-square = %5.1f, d.f. = %d\n", chiSquare, SESSION_ROWS - 1); #if (SESSION_ROWS == 11) printf(" .05 p value = 18.3, chi-square should be less\n"); #elif (SESSION_ROWS == 211) printf(".05 p value = 244.8, chi-square should be less\n"); #elif (SESSION_ROWS == 5981) printf(".05 p value = 6161.0, chi-square should be less\n"); #elif (SESSION_ROWS == 3) printf(".05 p value = 6.0, chi-square should be less\n"); #elif (SESSION_ROWS == 2861) printf(".05 p value = 2985.5, chi-square should be less\n"); #endif printf("\n"); return ret; } #endif /* SESSION_STATS */ #else /* NO_SESSION_CACHE */ WOLFSSL_SESSION* ClientSessionToSession(const WOLFSSL_SESSION* session) { return (WOLFSSL_SESSION*)session; } /* No session cache version */ WOLFSSL_SESSION* wolfSSL_GetSession(WOLFSSL* ssl, byte* masterSecret, byte restoreSessionCerts) { (void)ssl; (void)masterSecret; (void)restoreSessionCerts; return NULL; } #endif /* NO_SESSION_CACHE */ /* call before SSL_connect, if verifying will add name check to date check and signature check */ WOLFSSL_ABI int wolfSSL_check_domain_name(WOLFSSL* ssl, const char* dn) { WOLFSSL_ENTER("wolfSSL_check_domain_name"); if (ssl == NULL || dn == NULL) { WOLFSSL_MSG("Bad function argument: NULL"); return WOLFSSL_FAILURE; } if (ssl->buffers.domainName.buffer) XFREE(ssl->buffers.domainName.buffer, ssl->heap, DYNAMIC_TYPE_DOMAIN); ssl->buffers.domainName.length = (word32)XSTRLEN(dn); ssl->buffers.domainName.buffer = (byte*)XMALLOC( ssl->buffers.domainName.length + 1, ssl->heap, DYNAMIC_TYPE_DOMAIN); if (ssl->buffers.domainName.buffer) { unsigned char* domainName = ssl->buffers.domainName.buffer; XMEMCPY(domainName, dn, ssl->buffers.domainName.length); domainName[ssl->buffers.domainName.length] = '\0'; return WOLFSSL_SUCCESS; } else { ssl->error = MEMORY_ERROR; return WOLFSSL_FAILURE; } } /* turn on wolfSSL zlib compression returns WOLFSSL_SUCCESS for success, else error (not built in) */ int wolfSSL_set_compression(WOLFSSL* ssl) { WOLFSSL_ENTER("wolfSSL_set_compression"); (void)ssl; #ifdef HAVE_LIBZ ssl->options.usingCompression = 1; return WOLFSSL_SUCCESS; #else return NOT_COMPILED_IN; #endif } #ifndef USE_WINDOWS_API #ifndef NO_WRITEV /* simulate writev semantics, doesn't actually do block at a time though because of SSL_write behavior and because front adds may be small */ int wolfSSL_writev(WOLFSSL* ssl, const struct iovec* iov, int iovcnt) { #ifdef WOLFSSL_SMALL_STACK byte staticBuffer[1]; /* force heap usage */ #else byte staticBuffer[FILE_BUFFER_SIZE]; #endif byte* myBuffer = staticBuffer; int dynamic = 0; int sending = 0; int idx = 0; int i; int ret; WOLFSSL_ENTER("wolfSSL_writev"); for (i = 0; i < iovcnt; i++) sending += (int)iov[i].iov_len; if (sending > (int)sizeof(staticBuffer)) { myBuffer = (byte*)XMALLOC(sending, ssl->heap, DYNAMIC_TYPE_WRITEV); if (!myBuffer) return MEMORY_ERROR; dynamic = 1; } for (i = 0; i < iovcnt; i++) { XMEMCPY(&myBuffer[idx], iov[i].iov_base, iov[i].iov_len); idx += (int)iov[i].iov_len; } /* myBuffer may not be initialized fully, but the span up to the * sending length will be. */ PRAGMA_GCC_DIAG_PUSH; PRAGMA_GCC("GCC diagnostic ignored \"-Wmaybe-uninitialized\""); ret = wolfSSL_write(ssl, myBuffer, sending); PRAGMA_GCC_DIAG_POP; if (dynamic) XFREE(myBuffer, ssl->heap, DYNAMIC_TYPE_WRITEV); return ret; } #endif #endif #ifdef WOLFSSL_CALLBACKS typedef struct itimerval Itimerval; /* don't keep calling simple functions while setting up timer and signals if no inlining these are the next best */ #define AddTimes(a, b, c) \ do { \ c.tv_sec = a.tv_sec + b.tv_sec; \ c.tv_usec = a.tv_usec + b.tv_usec; \ if (c.tv_usec >= 1000000) { \ c.tv_sec++; \ c.tv_usec -= 1000000; \ } \ } while (0) #define SubtractTimes(a, b, c) \ do { \ c.tv_sec = a.tv_sec - b.tv_sec; \ c.tv_usec = a.tv_usec - b.tv_usec; \ if (c.tv_usec < 0) { \ c.tv_sec--; \ c.tv_usec += 1000000; \ } \ } while (0) #define CmpTimes(a, b, cmp) \ ((a.tv_sec == b.tv_sec) ? \ (a.tv_usec cmp b.tv_usec) : \ (a.tv_sec cmp b.tv_sec)) \ /* do nothing handler */ static void myHandler(int signo) { (void)signo; return; } static int wolfSSL_ex_wrapper(WOLFSSL* ssl, HandShakeCallBack hsCb, TimeoutCallBack toCb, WOLFSSL_TIMEVAL timeout) { int ret = WOLFSSL_FATAL_ERROR; int oldTimerOn = 0; /* was timer already on */ WOLFSSL_TIMEVAL startTime; WOLFSSL_TIMEVAL endTime; WOLFSSL_TIMEVAL totalTime; Itimerval myTimeout; Itimerval oldTimeout; /* if old timer adjust from total time to reset */ struct sigaction act, oact; #define ERR_OUT(x) { ssl->hsInfoOn = 0; ssl->toInfoOn = 0; return x; } if (hsCb) { ssl->hsInfoOn = 1; InitHandShakeInfo(&ssl->handShakeInfo, ssl); } if (toCb) { ssl->toInfoOn = 1; InitTimeoutInfo(&ssl->timeoutInfo); if (gettimeofday(&startTime, 0) < 0) ERR_OUT(GETTIME_ERROR); /* use setitimer to simulate getitimer, init 0 myTimeout */ myTimeout.it_interval.tv_sec = 0; myTimeout.it_interval.tv_usec = 0; myTimeout.it_value.tv_sec = 0; myTimeout.it_value.tv_usec = 0; if (setitimer(ITIMER_REAL, &myTimeout, &oldTimeout) < 0) ERR_OUT(SETITIMER_ERROR); if (oldTimeout.it_value.tv_sec || oldTimeout.it_value.tv_usec) { oldTimerOn = 1; /* is old timer going to expire before ours */ if (CmpTimes(oldTimeout.it_value, timeout, <)) { timeout.tv_sec = oldTimeout.it_value.tv_sec; timeout.tv_usec = oldTimeout.it_value.tv_usec; } } myTimeout.it_value.tv_sec = timeout.tv_sec; myTimeout.it_value.tv_usec = timeout.tv_usec; /* set up signal handler, don't restart socket send/recv */ act.sa_handler = myHandler; sigemptyset(&act.sa_mask); act.sa_flags = 0; #ifdef SA_INTERRUPT act.sa_flags |= SA_INTERRUPT; #endif if (sigaction(SIGALRM, &act, &oact) < 0) ERR_OUT(SIGACT_ERROR); if (setitimer(ITIMER_REAL, &myTimeout, 0) < 0) ERR_OUT(SETITIMER_ERROR); } /* do main work */ #ifndef NO_WOLFSSL_CLIENT if (ssl->options.side == WOLFSSL_CLIENT_END) ret = wolfSSL_connect(ssl); #endif #ifndef NO_WOLFSSL_SERVER if (ssl->options.side == WOLFSSL_SERVER_END) ret = wolfSSL_accept(ssl); #endif /* do callbacks */ if (toCb) { if (oldTimerOn) { gettimeofday(&endTime, 0); SubtractTimes(endTime, startTime, totalTime); /* adjust old timer for elapsed time */ if (CmpTimes(totalTime, oldTimeout.it_value, <)) SubtractTimes(oldTimeout.it_value, totalTime, oldTimeout.it_value); else { /* reset value to interval, may be off */ oldTimeout.it_value.tv_sec = oldTimeout.it_interval.tv_sec; oldTimeout.it_value.tv_usec =oldTimeout.it_interval.tv_usec; } /* keep iter the same whether there or not */ } /* restore old handler */ if (sigaction(SIGALRM, &oact, 0) < 0) ret = SIGACT_ERROR; /* more pressing error, stomp */ else /* use old settings which may turn off (expired or not there) */ if (setitimer(ITIMER_REAL, &oldTimeout, 0) < 0) ret = SETITIMER_ERROR; /* if we had a timeout call callback */ if (ssl->timeoutInfo.timeoutName[0]) { ssl->timeoutInfo.timeoutValue.tv_sec = timeout.tv_sec; ssl->timeoutInfo.timeoutValue.tv_usec = timeout.tv_usec; (toCb)(&ssl->timeoutInfo); } /* clean up */ FreeTimeoutInfo(&ssl->timeoutInfo, ssl->heap); ssl->toInfoOn = 0; } if (hsCb) { FinishHandShakeInfo(&ssl->handShakeInfo); (hsCb)(&ssl->handShakeInfo); ssl->hsInfoOn = 0; } return ret; } #ifndef NO_WOLFSSL_CLIENT int wolfSSL_connect_ex(WOLFSSL* ssl, HandShakeCallBack hsCb, TimeoutCallBack toCb, WOLFSSL_TIMEVAL timeout) { WOLFSSL_ENTER("wolfSSL_connect_ex"); return wolfSSL_ex_wrapper(ssl, hsCb, toCb, timeout); } #endif #ifndef NO_WOLFSSL_SERVER int wolfSSL_accept_ex(WOLFSSL* ssl, HandShakeCallBack hsCb, TimeoutCallBack toCb, WOLFSSL_TIMEVAL timeout) { WOLFSSL_ENTER("wolfSSL_accept_ex"); return wolfSSL_ex_wrapper(ssl, hsCb, toCb, timeout); } #endif #endif /* WOLFSSL_CALLBACKS */ #ifndef NO_PSK void wolfSSL_CTX_set_psk_client_callback(WOLFSSL_CTX* ctx, wc_psk_client_callback cb) { WOLFSSL_ENTER("SSL_CTX_set_psk_client_callback"); if (ctx == NULL) return; ctx->havePSK = 1; ctx->client_psk_cb = cb; } void wolfSSL_set_psk_client_callback(WOLFSSL* ssl,wc_psk_client_callback cb) { byte haveRSA = 1; int keySz = 0; WOLFSSL_ENTER("SSL_set_psk_client_callback"); if (ssl == NULL) return; ssl->options.havePSK = 1; ssl->options.client_psk_cb = cb; #ifdef NO_RSA haveRSA = 0; #endif #ifndef NO_CERTS keySz = ssl->buffers.keySz; #endif InitSuites(ssl->suites, ssl->version, keySz, haveRSA, TRUE, ssl->options.haveDH, ssl->options.haveECDSAsig, ssl->options.haveECC, ssl->options.haveStaticECC, ssl->options.haveFalconSig, ssl->options.haveAnon, ssl->options.side); } #ifdef OPENSSL_EXTRA /** * set call back function for psk session use * @param ssl a pointer to WOLFSSL structure * @param cb a function pointer to wc_psk_use_session_cb * @return none */ void wolfSSL_set_psk_use_session_callback(WOLFSSL* ssl, wc_psk_use_session_cb_func cb) { WOLFSSL_ENTER("wolfSSL_set_psk_use_session_callback"); ssl->options.havePSK = 1; ssl->options.session_psk_cb = cb; WOLFSSL_LEAVE("wolfSSL_set_psk_use_session_callback", WOLFSSL_SUCCESS); } #endif void wolfSSL_CTX_set_psk_server_callback(WOLFSSL_CTX* ctx, wc_psk_server_callback cb) { WOLFSSL_ENTER("SSL_CTX_set_psk_server_callback"); if (ctx == NULL) return; ctx->havePSK = 1; ctx->server_psk_cb = cb; } void wolfSSL_set_psk_server_callback(WOLFSSL* ssl,wc_psk_server_callback cb) { byte haveRSA = 1; int keySz = 0; WOLFSSL_ENTER("SSL_set_psk_server_callback"); if (ssl == NULL) return; ssl->options.havePSK = 1; ssl->options.server_psk_cb = cb; #ifdef NO_RSA haveRSA = 0; #endif #ifndef NO_CERTS keySz = ssl->buffers.keySz; #endif InitSuites(ssl->suites, ssl->version, keySz, haveRSA, TRUE, ssl->options.haveDH, ssl->options.haveECDSAsig, ssl->options.haveECC, ssl->options.haveStaticECC, ssl->options.haveFalconSig, ssl->options.haveAnon, ssl->options.side); } const char* wolfSSL_get_psk_identity_hint(const WOLFSSL* ssl) { WOLFSSL_ENTER("SSL_get_psk_identity_hint"); if (ssl == NULL || ssl->arrays == NULL) return NULL; return ssl->arrays->server_hint; } const char* wolfSSL_get_psk_identity(const WOLFSSL* ssl) { WOLFSSL_ENTER("SSL_get_psk_identity"); if (ssl == NULL || ssl->arrays == NULL) return NULL; return ssl->arrays->client_identity; } int wolfSSL_CTX_use_psk_identity_hint(WOLFSSL_CTX* ctx, const char* hint) { WOLFSSL_ENTER("SSL_CTX_use_psk_identity_hint"); if (hint == 0) ctx->server_hint[0] = '\0'; else { /* Qt does not call CTX_set_*_psk_callbacks where havePSK is set */ #ifdef WOLFSSL_QT ctx->havePSK=1; #endif XSTRNCPY(ctx->server_hint, hint, MAX_PSK_ID_LEN); ctx->server_hint[MAX_PSK_ID_LEN] = '\0'; /* null term */ } return WOLFSSL_SUCCESS; } int wolfSSL_use_psk_identity_hint(WOLFSSL* ssl, const char* hint) { WOLFSSL_ENTER("SSL_use_psk_identity_hint"); if (ssl == NULL || ssl->arrays == NULL) return WOLFSSL_FAILURE; if (hint == 0) ssl->arrays->server_hint[0] = 0; else { XSTRNCPY(ssl->arrays->server_hint, hint, sizeof(ssl->arrays->server_hint)-1); ssl->arrays->server_hint[sizeof(ssl->arrays->server_hint)-1] = '\0'; } return WOLFSSL_SUCCESS; } void* wolfSSL_get_psk_callback_ctx(WOLFSSL* ssl) { return ssl ? ssl->options.psk_ctx : NULL; } void* wolfSSL_CTX_get_psk_callback_ctx(WOLFSSL_CTX* ctx) { return ctx ? ctx->psk_ctx : NULL; } int wolfSSL_set_psk_callback_ctx(WOLFSSL* ssl, void* psk_ctx) { if (ssl == NULL) return WOLFSSL_FAILURE; ssl->options.psk_ctx = psk_ctx; return WOLFSSL_SUCCESS; } int wolfSSL_CTX_set_psk_callback_ctx(WOLFSSL_CTX* ctx, void* psk_ctx) { if (ctx == NULL) return WOLFSSL_FAILURE; ctx->psk_ctx = psk_ctx; return WOLFSSL_SUCCESS; } #endif /* NO_PSK */ #ifdef HAVE_ANON int wolfSSL_CTX_allow_anon_cipher(WOLFSSL_CTX* ctx) { WOLFSSL_ENTER("wolfSSL_CTX_allow_anon_cipher"); if (ctx == NULL) return WOLFSSL_FAILURE; ctx->haveAnon = 1; return WOLFSSL_SUCCESS; } #endif /* HAVE_ANON */ #ifndef NO_CERTS /* used to be defined on NO_FILESYSTEM only, but are generally useful */ int wolfSSL_CTX_load_verify_buffer_ex(WOLFSSL_CTX* ctx, const unsigned char* in, long sz, int format, int userChain, word32 flags) { int verify; int ret = WOLFSSL_FAILURE; WOLFSSL_ENTER("wolfSSL_CTX_load_verify_buffer_ex"); verify = GET_VERIFY_SETTING_CTX(ctx); if (flags & WOLFSSL_LOAD_FLAG_DATE_ERR_OKAY) verify = VERIFY_SKIP_DATE; if (format == WOLFSSL_FILETYPE_PEM) ret = ProcessChainBuffer(ctx, in, sz, format, CA_TYPE, NULL, verify); else ret = ProcessBuffer(ctx, in, sz, format, CA_TYPE, NULL, NULL, userChain, verify); #if defined(WOLFSSL_TRUST_PEER_CERT) && defined(OPENSSL_COMPATIBLE_DEFAULTS) if (ret == WOLFSSL_SUCCESS) ret = wolfSSL_CTX_trust_peer_buffer(ctx, in, sz, format); #endif WOLFSSL_LEAVE("wolfSSL_CTX_load_verify_buffer_ex", ret); return ret; } /* wolfSSL extension allows DER files to be loaded from buffers as well */ int wolfSSL_CTX_load_verify_buffer(WOLFSSL_CTX* ctx, const unsigned char* in, long sz, int format) { return wolfSSL_CTX_load_verify_buffer_ex(ctx, in, sz, format, 0, WOLFSSL_LOAD_VERIFY_DEFAULT_FLAGS); } int wolfSSL_CTX_load_verify_chain_buffer_format(WOLFSSL_CTX* ctx, const unsigned char* in, long sz, int format) { return wolfSSL_CTX_load_verify_buffer_ex(ctx, in, sz, format, 1, WOLFSSL_LOAD_VERIFY_DEFAULT_FLAGS); } #ifdef WOLFSSL_TRUST_PEER_CERT int wolfSSL_CTX_trust_peer_buffer(WOLFSSL_CTX* ctx, const unsigned char* in, long sz, int format) { WOLFSSL_ENTER("wolfSSL_CTX_trust_peer_buffer"); /* sanity check on arguments */ if (sz < 0 || in == NULL || ctx == NULL) { return BAD_FUNC_ARG; } if (format == WOLFSSL_FILETYPE_PEM) return ProcessChainBuffer(ctx, in, sz, format, TRUSTED_PEER_TYPE, NULL, GET_VERIFY_SETTING_CTX(ctx)); else return ProcessBuffer(ctx, in, sz, format, TRUSTED_PEER_TYPE, NULL, NULL, 0, GET_VERIFY_SETTING_CTX(ctx)); } #endif /* WOLFSSL_TRUST_PEER_CERT */ int wolfSSL_CTX_use_certificate_buffer(WOLFSSL_CTX* ctx, const unsigned char* in, long sz, int format) { int ret = WOLFSSL_FAILURE; WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_buffer"); ret = ProcessBuffer(ctx, in, sz, format, CERT_TYPE, NULL, NULL, 0, GET_VERIFY_SETTING_CTX(ctx)); WOLFSSL_LEAVE("wolfSSL_CTX_use_certificate_buffer", ret); return ret; } int wolfSSL_CTX_use_PrivateKey_buffer(WOLFSSL_CTX* ctx, const unsigned char* in, long sz, int format) { int ret = WOLFSSL_FAILURE; WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey_buffer"); ret = ProcessBuffer(ctx, in, sz, format, PRIVATEKEY_TYPE, NULL, NULL, 0, GET_VERIFY_SETTING_CTX(ctx)); WOLFSSL_LEAVE("wolfSSL_CTX_use_PrivateKey_buffer", ret); return ret; } #ifdef WOLF_PRIVATE_KEY_ID int wolfSSL_CTX_use_PrivateKey_id(WOLFSSL_CTX* ctx, const unsigned char* id, long sz, int devId, long keySz) { int ret = wolfSSL_CTX_use_PrivateKey_Id(ctx, id, sz, devId); if (ret == WOLFSSL_SUCCESS) ctx->privateKeySz = (word32)keySz; return ret; } int wolfSSL_CTX_use_PrivateKey_Id(WOLFSSL_CTX* ctx, const unsigned char* id, long sz, int devId) { int ret = WOLFSSL_FAILURE; FreeDer(&ctx->privateKey); if (AllocDer(&ctx->privateKey, (word32)sz, PRIVATEKEY_TYPE, ctx->heap) == 0) { XMEMCPY(ctx->privateKey->buffer, id, sz); ctx->privateKeyId = 1; if (devId != INVALID_DEVID) ctx->privateKeyDevId = devId; else ctx->privateKeyDevId = ctx->devId; ret = WOLFSSL_SUCCESS; } return ret; } int wolfSSL_CTX_use_PrivateKey_Label(WOLFSSL_CTX* ctx, const char* label, int devId) { int ret = WOLFSSL_FAILURE; word32 sz = (word32)XSTRLEN(label) + 1; FreeDer(&ctx->privateKey); if (AllocDer(&ctx->privateKey, (word32)sz, PRIVATEKEY_TYPE, ctx->heap) == 0) { XMEMCPY(ctx->privateKey->buffer, label, sz); ctx->privateKeyLabel = 1; if (devId != INVALID_DEVID) ctx->privateKeyDevId = devId; else ctx->privateKeyDevId = ctx->devId; ret = WOLFSSL_SUCCESS; } return ret; } #endif /* WOLF_PRIVATE_KEY_ID */ int wolfSSL_CTX_use_certificate_chain_buffer_format(WOLFSSL_CTX* ctx, const unsigned char* in, long sz, int format) { WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_chain_buffer_format"); return ProcessBuffer(ctx, in, sz, format, CERT_TYPE, NULL, NULL, 1, GET_VERIFY_SETTING_CTX(ctx)); } int wolfSSL_CTX_use_certificate_chain_buffer(WOLFSSL_CTX* ctx, const unsigned char* in, long sz) { return wolfSSL_CTX_use_certificate_chain_buffer_format(ctx, in, sz, WOLFSSL_FILETYPE_PEM); } #ifndef NO_DH /* server wrapper for ctx or ssl Diffie-Hellman parameters */ static int wolfSSL_SetTmpDH_buffer_wrapper(WOLFSSL_CTX* ctx, WOLFSSL* ssl, const unsigned char* buf, long sz, int format) { DerBuffer* der = NULL; int ret = 0; word32 pSz = MAX_DH_SIZE; word32 gSz = MAX_DH_SIZE; #ifdef WOLFSSL_SMALL_STACK byte* p = NULL; byte* g = NULL; #else byte p[MAX_DH_SIZE]; byte g[MAX_DH_SIZE]; #endif if (ctx == NULL || buf == NULL) return BAD_FUNC_ARG; ret = AllocDer(&der, 0, DH_PARAM_TYPE, ctx->heap); if (ret != 0) { return ret; } der->buffer = (byte*)buf; der->length = (word32)sz; #ifdef WOLFSSL_SMALL_STACK p = (byte*)XMALLOC(pSz, NULL, DYNAMIC_TYPE_PUBLIC_KEY); g = (byte*)XMALLOC(gSz, NULL, DYNAMIC_TYPE_PUBLIC_KEY); if (p == NULL || g == NULL) { XFREE(p, NULL, DYNAMIC_TYPE_PUBLIC_KEY); XFREE(g, NULL, DYNAMIC_TYPE_PUBLIC_KEY); return MEMORY_E; } #endif if (format != WOLFSSL_FILETYPE_ASN1 && format != WOLFSSL_FILETYPE_PEM) ret = WOLFSSL_BAD_FILETYPE; else { if (format == WOLFSSL_FILETYPE_PEM) { #ifdef WOLFSSL_PEM_TO_DER FreeDer(&der); ret = PemToDer(buf, sz, DH_PARAM_TYPE, &der, ctx->heap, NULL, NULL); if (ret < 0) { /* Also try X9.42 format */ ret = PemToDer(buf, sz, X942_PARAM_TYPE, &der, ctx->heap, NULL, NULL); } #ifdef WOLFSSL_WPAS #ifndef NO_DSA if (ret < 0) { ret = PemToDer(buf, sz, DSA_PARAM_TYPE, &der, ctx->heap, NULL, NULL); } #endif #endif /* WOLFSSL_WPAS */ #else ret = NOT_COMPILED_IN; #endif /* WOLFSSL_PEM_TO_DER */ } if (ret == 0) { if (wc_DhParamsLoad(der->buffer, der->length, p, &pSz, g, &gSz) < 0) ret = WOLFSSL_BAD_FILETYPE; else if (ssl) ret = wolfSSL_SetTmpDH(ssl, p, pSz, g, gSz); else ret = wolfSSL_CTX_SetTmpDH(ctx, p, pSz, g, gSz); } } FreeDer(&der); #ifdef WOLFSSL_SMALL_STACK XFREE(p, NULL, DYNAMIC_TYPE_PUBLIC_KEY); XFREE(g, NULL, DYNAMIC_TYPE_PUBLIC_KEY); #endif return ret; } /* server Diffie-Hellman parameters, WOLFSSL_SUCCESS on ok */ int wolfSSL_SetTmpDH_buffer(WOLFSSL* ssl, const unsigned char* buf, long sz, int format) { if (ssl == NULL) return BAD_FUNC_ARG; return wolfSSL_SetTmpDH_buffer_wrapper(ssl->ctx, ssl, buf, sz, format); } /* server ctx Diffie-Hellman parameters, WOLFSSL_SUCCESS on ok */ int wolfSSL_CTX_SetTmpDH_buffer(WOLFSSL_CTX* ctx, const unsigned char* buf, long sz, int format) { return wolfSSL_SetTmpDH_buffer_wrapper(ctx, NULL, buf, sz, format); } #endif /* NO_DH */ int wolfSSL_use_certificate_buffer(WOLFSSL* ssl, const unsigned char* in, long sz, int format) { WOLFSSL_ENTER("wolfSSL_use_certificate_buffer"); if (ssl == NULL) return BAD_FUNC_ARG; return ProcessBuffer(ssl->ctx, in, sz, format, CERT_TYPE, ssl, NULL, 0, GET_VERIFY_SETTING_SSL(ssl)); } int wolfSSL_use_PrivateKey_buffer(WOLFSSL* ssl, const unsigned char* in, long sz, int format) { WOLFSSL_ENTER("wolfSSL_use_PrivateKey_buffer"); if (ssl == NULL) return BAD_FUNC_ARG; return ProcessBuffer(ssl->ctx, in, sz, format, PRIVATEKEY_TYPE, ssl, NULL, 0, GET_VERIFY_SETTING_SSL(ssl)); } #ifdef WOLF_PRIVATE_KEY_ID int wolfSSL_use_PrivateKey_id(WOLFSSL* ssl, const unsigned char* id, long sz, int devId, long keySz) { int ret = wolfSSL_use_PrivateKey_Id(ssl, id, sz, devId); if (ret == WOLFSSL_SUCCESS) ssl->buffers.keySz = (word32)keySz; return ret; } int wolfSSL_use_PrivateKey_Id(WOLFSSL* ssl, const unsigned char* id, long sz, int devId) { int ret = WOLFSSL_FAILURE; if (ssl->buffers.weOwnKey) FreeDer(&ssl->buffers.key); if (AllocDer(&ssl->buffers.key, (word32)sz, PRIVATEKEY_TYPE, ssl->heap) == 0) { XMEMCPY(ssl->buffers.key->buffer, id, sz); ssl->buffers.weOwnKey = 1; ssl->buffers.keyId = 1; if (devId != INVALID_DEVID) ssl->buffers.keyDevId = devId; else ssl->buffers.keyDevId = ssl->devId; ret = WOLFSSL_SUCCESS; } return ret; } int wolfSSL_use_PrivateKey_Label(WOLFSSL* ssl, const char* label, int devId) { int ret = WOLFSSL_FAILURE; word32 sz = (word32)XSTRLEN(label) + 1; if (ssl->buffers.weOwnKey) FreeDer(&ssl->buffers.key); if (AllocDer(&ssl->buffers.key, (word32)sz, PRIVATEKEY_TYPE, ssl->heap) == 0) { XMEMCPY(ssl->buffers.key->buffer, label, sz); ssl->buffers.weOwnKey = 1; ssl->buffers.keyLabel = 1; if (devId != INVALID_DEVID) ssl->buffers.keyDevId = devId; else ssl->buffers.keyDevId = ssl->devId; ret = WOLFSSL_SUCCESS; } return ret; } #endif /* WOLF_PRIVATE_KEY_ID */ int wolfSSL_use_certificate_chain_buffer_format(WOLFSSL* ssl, const unsigned char* in, long sz, int format) { WOLFSSL_ENTER("wolfSSL_use_certificate_chain_buffer_format"); if (ssl == NULL) return BAD_FUNC_ARG; return ProcessBuffer(ssl->ctx, in, sz, format, CERT_TYPE, ssl, NULL, 1, GET_VERIFY_SETTING_SSL(ssl)); } int wolfSSL_use_certificate_chain_buffer(WOLFSSL* ssl, const unsigned char* in, long sz) { return wolfSSL_use_certificate_chain_buffer_format(ssl, in, sz, WOLFSSL_FILETYPE_PEM); } /* unload any certs or keys that SSL owns, leave CTX as is WOLFSSL_SUCCESS on ok */ int wolfSSL_UnloadCertsKeys(WOLFSSL* ssl) { if (ssl == NULL) { WOLFSSL_MSG("Null function arg"); return BAD_FUNC_ARG; } if (ssl->buffers.weOwnCert && !ssl->keepCert) { WOLFSSL_MSG("Unloading cert"); FreeDer(&ssl->buffers.certificate); #ifdef KEEP_OUR_CERT wolfSSL_X509_free(ssl->ourCert); ssl->ourCert = NULL; #endif ssl->buffers.weOwnCert = 0; } if (ssl->buffers.weOwnCertChain) { WOLFSSL_MSG("Unloading cert chain"); FreeDer(&ssl->buffers.certChain); ssl->buffers.weOwnCertChain = 0; } if (ssl->buffers.weOwnKey) { WOLFSSL_MSG("Unloading key"); ForceZero(ssl->buffers.key->buffer, ssl->buffers.key->length); FreeDer(&ssl->buffers.key); ssl->buffers.weOwnKey = 0; } return WOLFSSL_SUCCESS; } int wolfSSL_CTX_UnloadCAs(WOLFSSL_CTX* ctx) { WOLFSSL_ENTER("wolfSSL_CTX_UnloadCAs"); if (ctx == NULL) return BAD_FUNC_ARG; return wolfSSL_CertManagerUnloadCAs(ctx->cm); } #ifdef WOLFSSL_TRUST_PEER_CERT int wolfSSL_CTX_Unload_trust_peers(WOLFSSL_CTX* ctx) { WOLFSSL_ENTER("wolfSSL_CTX_Unload_trust_peers"); if (ctx == NULL) return BAD_FUNC_ARG; return wolfSSL_CertManagerUnload_trust_peers(ctx->cm); } #ifdef WOLFSSL_LOCAL_X509_STORE int wolfSSL_Unload_trust_peers(WOLFSSL* ssl) { WOLFSSL_ENTER("wolfSSL_CTX_Unload_trust_peers"); if (ssl == NULL) return BAD_FUNC_ARG; return wolfSSL_CertManagerUnload_trust_peers(SSL_CM(ssl)); } #endif /* WOLFSSL_LOCAL_X509_STORE */ #endif /* WOLFSSL_TRUST_PEER_CERT */ /* old NO_FILESYSTEM end */ #endif /* !NO_CERTS */ #ifdef OPENSSL_EXTRA int wolfSSL_add_all_algorithms(void) { WOLFSSL_ENTER("wolfSSL_add_all_algorithms"); if (initRefCount != 0 || wolfSSL_Init() == WOLFSSL_SUCCESS) return WOLFSSL_SUCCESS; else return WOLFSSL_FATAL_ERROR; } int wolfSSL_OpenSSL_add_all_algorithms_noconf(void) { WOLFSSL_ENTER("wolfSSL_OpenSSL_add_all_algorithms_noconf"); if (wolfSSL_add_all_algorithms() == WOLFSSL_FATAL_ERROR) return WOLFSSL_FATAL_ERROR; return WOLFSSL_SUCCESS; } int wolfSSL_OpenSSL_add_all_algorithms_conf(void) { WOLFSSL_ENTER("wolfSSL_OpenSSL_add_all_algorithms_conf"); /* This function is currently the same as wolfSSL_OpenSSL_add_all_algorithms_noconf since we do not employ the use of a wolfssl.cnf type configuration file and is only used for OpenSSL compatability. */ if (wolfSSL_add_all_algorithms() == WOLFSSL_FATAL_ERROR) { return WOLFSSL_FATAL_ERROR; } return WOLFSSL_SUCCESS; } /* returns previous set cache size which stays constant */ long wolfSSL_CTX_sess_set_cache_size(WOLFSSL_CTX* ctx, long sz) { /* cache size fixed at compile time in wolfSSL */ (void)ctx; (void)sz; WOLFSSL_MSG("session cache is set at compile time"); #ifndef NO_SESSION_CACHE return (long)(SESSIONS_PER_ROW * SESSION_ROWS); #else return 0; #endif } #endif #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) void wolfSSL_CTX_set_quiet_shutdown(WOLFSSL_CTX* ctx, int mode) { WOLFSSL_ENTER("wolfSSL_CTX_set_quiet_shutdown"); if (mode) ctx->quietShutdown = 1; } void wolfSSL_set_quiet_shutdown(WOLFSSL* ssl, int mode) { WOLFSSL_ENTER("wolfSSL_CTX_set_quiet_shutdown"); if (mode) ssl->options.quietShutdown = 1; } #endif /* OPENSSL_EXTRA || WOLFSSL_EXTRA || WOLFSSL_WPAS_SMALL */ #ifdef OPENSSL_EXTRA #ifndef NO_BIO void wolfSSL_set_bio(WOLFSSL* ssl, WOLFSSL_BIO* rd, WOLFSSL_BIO* wr) { WOLFSSL_ENTER("wolfSSL_set_bio"); if (ssl == NULL) { WOLFSSL_MSG("Bad argument, ssl was NULL"); return; } /* free any existing WOLFSSL_BIOs in use but don't free those in * a chain */ if (ssl->biord != NULL) { if (ssl->biord != ssl->biowr) { if (ssl->biowr != NULL && ssl->biowr->prev != NULL) wolfSSL_BIO_free(ssl->biowr); ssl->biowr = NULL; } if (ssl->biord->prev != NULL) wolfSSL_BIO_free(ssl->biord); ssl->biord = NULL; } /* set flag obviously */ if (rd && !(rd->flags & WOLFSSL_BIO_FLAG_READ)) rd->flags |= WOLFSSL_BIO_FLAG_READ; if (wr && !(wr->flags & WOLFSSL_BIO_FLAG_WRITE)) wr->flags |= WOLFSSL_BIO_FLAG_WRITE; ssl->biord = rd; ssl->biowr = wr; /* set SSL to use BIO callbacks instead */ if (((ssl->cbioFlag & WOLFSSL_CBIO_RECV) == 0)) { ssl->CBIORecv = BioReceive; } if (((ssl->cbioFlag & WOLFSSL_CBIO_SEND) == 0)) { ssl->CBIOSend = BioSend; } /* User programs should always retry reading from these BIOs */ if (rd) { /* User writes to rd */ BIO_set_retry_write(rd); } if (wr) { /* User reads from wr */ BIO_set_retry_read(wr); } } #endif /* !NO_BIO */ #endif /* OPENSSL_EXTRA */ #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EXTRA) void wolfSSL_CTX_set_client_CA_list(WOLFSSL_CTX* ctx, WOLF_STACK_OF(WOLFSSL_X509_NAME)* names) { WOLFSSL_ENTER("wolfSSL_CTX_set_client_CA_list"); if (ctx != NULL) { wolfSSL_sk_X509_NAME_pop_free(ctx->ca_names, NULL); ctx->ca_names = names; } } void wolfSSL_set_client_CA_list(WOLFSSL* ssl, WOLF_STACK_OF(WOLFSSL_X509_NAME)* names) { WOLFSSL_ENTER("wolfSSL_set_client_CA_list"); if (ssl != NULL) { if (ssl->ca_names != ssl->ctx->ca_names) wolfSSL_sk_X509_NAME_pop_free(ssl->ca_names, NULL); ssl->ca_names = names; } } #ifdef OPENSSL_EXTRA /* registers client cert callback, called during handshake if server requests client auth but user has not loaded client cert/key */ void wolfSSL_CTX_set_client_cert_cb(WOLFSSL_CTX *ctx, client_cert_cb cb) { WOLFSSL_ENTER("wolfSSL_CTX_set_client_cert_cb"); if (ctx != NULL) { ctx->CBClientCert = cb; } } void wolfSSL_CTX_set_cert_cb(WOLFSSL_CTX* ctx, CertSetupCallback cb, void *arg) { WOLFSSL_ENTER("wolfSSL_CTX_set_cert_cb"); if (ctx == NULL) return; ctx->certSetupCb = cb; ctx->certSetupCbArg = arg; } /** * Internal wrapper for calling certSetupCb * @param ssl The SSL/TLS Object * @return 0 on success */ int CertSetupCbWrapper(WOLFSSL* ssl) { int ret = 0; if (ssl->ctx->certSetupCb != NULL) { WOLFSSL_MSG("Calling user cert setup callback"); ret = ssl->ctx->certSetupCb(ssl, ssl->ctx->certSetupCbArg); if (ret == 1) { WOLFSSL_MSG("User cert callback returned success"); ret = 0; } else if (ret == 0) { SendAlert(ssl, alert_fatal, internal_error); ret = CLIENT_CERT_CB_ERROR; } else if (ret < 0) { ret = WOLFSSL_ERROR_WANT_X509_LOOKUP; } else { WOLFSSL_MSG("Unexpected user callback return"); ret = CLIENT_CERT_CB_ERROR; } } return ret; } #endif /* OPENSSL_EXTRA */ #endif /* OPENSSL_EXTRA || WOLFSSL_EXTRA || HAVE_WEBSERVER */ #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EXTRA) WOLF_STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_CTX_get_client_CA_list( const WOLFSSL_CTX *ctx) { WOLFSSL_ENTER("wolfSSL_CTX_get_client_CA_list"); if (ctx == NULL) { WOLFSSL_MSG("Bad argument passed to wolfSSL_CTX_get_client_CA_list"); return NULL; } return ctx->ca_names; } /* returns the CA's set on server side or the CA's sent from server when * on client side */ WOLF_STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_get_client_CA_list( const WOLFSSL* ssl) { WOLFSSL_ENTER("wolfSSL_get_client_CA_list"); if (ssl == NULL) { WOLFSSL_MSG("Bad argument passed to wolfSSL_get_client_CA_list"); return NULL; } return SSL_CA_NAMES(ssl); } #if !defined(NO_CERTS) int wolfSSL_CTX_add_client_CA(WOLFSSL_CTX* ctx, WOLFSSL_X509* x509) { WOLFSSL_X509_NAME *nameCopy = NULL; WOLFSSL_ENTER("wolfSSL_CTX_add_client_CA"); if (ctx == NULL || x509 == NULL){ WOLFSSL_MSG("Bad argument"); return WOLFSSL_FAILURE; } if (ctx->ca_names == NULL) { ctx->ca_names = wolfSSL_sk_X509_NAME_new(NULL); if (ctx->ca_names == NULL) { WOLFSSL_MSG("wolfSSL_sk_X509_NAME_new error"); return WOLFSSL_FAILURE; } } nameCopy = wolfSSL_X509_NAME_dup(wolfSSL_X509_get_subject_name(x509)); if (nameCopy == NULL) { WOLFSSL_MSG("wolfSSL_X509_NAME_dup error"); return WOLFSSL_FAILURE; } if (wolfSSL_sk_X509_NAME_push(ctx->ca_names, nameCopy) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("wolfSSL_sk_X509_NAME_push error"); wolfSSL_X509_NAME_free(nameCopy); return WOLFSSL_FAILURE; } return WOLFSSL_SUCCESS; } #endif #ifndef NO_BIO #if !defined(NO_RSA) && !defined(NO_CERTS) WOLF_STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_load_client_CA_file(const char* fname) { /* The webserver build is using this to load a CA into the server * for client authentication as an option. Have this return NULL in * that case. If OPENSSL_EXTRA is enabled, go ahead and include * the function. */ #ifdef OPENSSL_EXTRA WOLFSSL_STACK *list = NULL; WOLFSSL_BIO* bio = NULL; WOLFSSL_X509 *cert = NULL; WOLFSSL_X509_NAME *nameCopy = NULL; unsigned long err = WOLFSSL_FAILURE; WOLFSSL_ENTER("wolfSSL_load_client_CA_file"); bio = wolfSSL_BIO_new_file(fname, "rb"); if (bio == NULL) { WOLFSSL_MSG("wolfSSL_BIO_new_file error"); goto cleanup; } list = wolfSSL_sk_X509_NAME_new(NULL); if (list == NULL) { WOLFSSL_MSG("wolfSSL_sk_X509_NAME_new error"); goto cleanup; } /* Read each certificate in the chain out of the file. */ while (wolfSSL_PEM_read_bio_X509(bio, &cert, NULL, NULL) != NULL) { /* Need a persistent copy of the subject name. */ nameCopy = wolfSSL_X509_NAME_dup( wolfSSL_X509_get_subject_name(cert)); if (nameCopy == NULL) { WOLFSSL_MSG("wolfSSL_X509_NAME_dup error"); goto cleanup; } /* * Original cert will be freed so make sure not to try to access * it in the future. */ nameCopy->x509 = NULL; if (wolfSSL_sk_X509_NAME_push(list, nameCopy) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("wolfSSL_sk_X509_NAME_push error"); /* Do free in loop because nameCopy is now responsibility * of list to free and adding jumps to cleanup after this * might result in a double free. */ wolfSSL_X509_NAME_free(nameCopy); goto cleanup; } wolfSSL_X509_free(cert); cert = NULL; } CLEAR_ASN_NO_PEM_HEADER_ERROR(err); err = WOLFSSL_SUCCESS; cleanup: wolfSSL_X509_free(cert); wolfSSL_BIO_free(bio); if (err != WOLFSSL_SUCCESS) { /* We failed so return NULL */ wolfSSL_sk_X509_NAME_pop_free(list, NULL); list = NULL; } return list; #else (void)fname; return NULL; #endif } #endif #endif /* !NO_BIO */ #endif /* OPENSSL_EXTRA || WOLFSSL_EXTRA */ #ifdef OPENSSL_EXTRA #ifndef NO_WOLFSSL_STUB int wolfSSL_CTX_set_default_verify_paths(WOLFSSL_CTX* ctx) { /* TODO:, not needed in goahead */ (void)ctx; WOLFSSL_STUB("SSL_CTX_set_default_verify_paths"); return SSL_NOT_IMPLEMENTED; } #endif #if defined(WOLFCRYPT_HAVE_SRP) && !defined(NO_SHA256) \ && !defined(WC_NO_RNG) static const byte srp_N[] = { 0xEE, 0xAF, 0x0A, 0xB9, 0xAD, 0xB3, 0x8D, 0xD6, 0x9C, 0x33, 0xF8, 0x0A, 0xFA, 0x8F, 0xC5, 0xE8, 0x60, 0x72, 0x61, 0x87, 0x75, 0xFF, 0x3C, 0x0B, 0x9E, 0xA2, 0x31, 0x4C, 0x9C, 0x25, 0x65, 0x76, 0xD6, 0x74, 0xDF, 0x74, 0x96, 0xEA, 0x81, 0xD3, 0x38, 0x3B, 0x48, 0x13, 0xD6, 0x92, 0xC6, 0xE0, 0xE0, 0xD5, 0xD8, 0xE2, 0x50, 0xB9, 0x8B, 0xE4, 0x8E, 0x49, 0x5C, 0x1D, 0x60, 0x89, 0xDA, 0xD1, 0x5D, 0xC7, 0xD7, 0xB4, 0x61, 0x54, 0xD6, 0xB6, 0xCE, 0x8E, 0xF4, 0xAD, 0x69, 0xB1, 0x5D, 0x49, 0x82, 0x55, 0x9B, 0x29, 0x7B, 0xCF, 0x18, 0x85, 0xC5, 0x29, 0xF5, 0x66, 0x66, 0x0E, 0x57, 0xEC, 0x68, 0xED, 0xBC, 0x3C, 0x05, 0x72, 0x6C, 0xC0, 0x2F, 0xD4, 0xCB, 0xF4, 0x97, 0x6E, 0xAA, 0x9A, 0xFD, 0x51, 0x38, 0xFE, 0x83, 0x76, 0x43, 0x5B, 0x9F, 0xC6, 0x1D, 0x2F, 0xC0, 0xEB, 0x06, 0xE3 }; static const byte srp_g[] = { 0x02 }; int wolfSSL_CTX_set_srp_username(WOLFSSL_CTX* ctx, char* username) { int r = 0; SrpSide srp_side = SRP_CLIENT_SIDE; byte salt[SRP_SALT_SIZE]; WOLFSSL_ENTER("wolfSSL_CTX_set_srp_username"); if (ctx == NULL || ctx->srp == NULL || username==NULL) return SSL_FAILURE; if (ctx->method->side == WOLFSSL_SERVER_END){ srp_side = SRP_SERVER_SIDE; } else if (ctx->method->side == WOLFSSL_CLIENT_END){ srp_side = SRP_CLIENT_SIDE; } else { WOLFSSL_MSG("Init CTX failed"); return SSL_FAILURE; } if (wc_SrpInit(ctx->srp, SRP_TYPE_SHA256, srp_side) < 0) { WOLFSSL_MSG("Init SRP CTX failed"); XFREE(ctx->srp, ctx->heap, DYNAMIC_TYPE_SRP); ctx->srp = NULL; return SSL_FAILURE; } r = wc_SrpSetUsername(ctx->srp, (const byte*)username, (word32)XSTRLEN(username)); if (r < 0) { WOLFSSL_MSG("fail to set srp username."); return SSL_FAILURE; } /* if wolfSSL_CTX_set_srp_password has already been called, */ /* execute wc_SrpSetPassword here */ if (ctx->srp_password != NULL) { WC_RNG rng; if (wc_InitRng(&rng) < 0){ WOLFSSL_MSG("wc_InitRng failed"); return SSL_FAILURE; } XMEMSET(salt, 0, sizeof(salt)/sizeof(salt[0])); r = wc_RNG_GenerateBlock(&rng, salt, sizeof(salt)/sizeof(salt[0])); wc_FreeRng(&rng); if (r < 0) { WOLFSSL_MSG("wc_RNG_GenerateBlock failed"); return SSL_FAILURE; } if (wc_SrpSetParams(ctx->srp, srp_N, sizeof(srp_N)/sizeof(srp_N[0]), srp_g, sizeof(srp_g)/sizeof(srp_g[0]), salt, sizeof(salt)/sizeof(salt[0])) < 0) { WOLFSSL_MSG("wc_SrpSetParam failed"); return SSL_FAILURE; } r = wc_SrpSetPassword(ctx->srp, (const byte*)ctx->srp_password, (word32)XSTRLEN((char *)ctx->srp_password)); if (r < 0) { WOLFSSL_MSG("fail to set srp password."); return SSL_FAILURE; } XFREE(ctx->srp_password, ctx->heap, DYNAMIC_TYPE_SRP); ctx->srp_password = NULL; } return WOLFSSL_SUCCESS; } int wolfSSL_CTX_set_srp_password(WOLFSSL_CTX* ctx, char* password) { int r; byte salt[SRP_SALT_SIZE]; WOLFSSL_ENTER("wolfSSL_CTX_set_srp_password"); if (ctx == NULL || ctx->srp == NULL || password == NULL) return SSL_FAILURE; if (ctx->srp->user != NULL) { WC_RNG rng; if (wc_InitRng(&rng) < 0) { WOLFSSL_MSG("wc_InitRng failed"); return SSL_FAILURE; } XMEMSET(salt, 0, sizeof(salt)/sizeof(salt[0])); r = wc_RNG_GenerateBlock(&rng, salt, sizeof(salt)/sizeof(salt[0])); wc_FreeRng(&rng); if (r < 0) { WOLFSSL_MSG("wc_RNG_GenerateBlock failed"); return SSL_FAILURE; } if (wc_SrpSetParams(ctx->srp, srp_N, sizeof(srp_N)/sizeof(srp_N[0]), srp_g, sizeof(srp_g)/sizeof(srp_g[0]), salt, sizeof(salt)/sizeof(salt[0])) < 0){ WOLFSSL_MSG("wc_SrpSetParam failed"); wc_FreeRng(&rng); return SSL_FAILURE; } r = wc_SrpSetPassword(ctx->srp, (const byte*)password, (word32)XSTRLEN(password)); if (r < 0) { WOLFSSL_MSG("wc_SrpSetPassword failed."); wc_FreeRng(&rng); return SSL_FAILURE; } if (ctx->srp_password != NULL){ XFREE(ctx->srp_password,NULL, DYNAMIC_TYPE_SRP); ctx->srp_password = NULL; } wc_FreeRng(&rng); } else { /* save password for wolfSSL_set_srp_username */ if (ctx->srp_password != NULL) XFREE(ctx->srp_password,ctx->heap, DYNAMIC_TYPE_SRP); ctx->srp_password = (byte*)XMALLOC(XSTRLEN(password) + 1, ctx->heap, DYNAMIC_TYPE_SRP); if (ctx->srp_password == NULL){ WOLFSSL_MSG("memory allocation error"); return SSL_FAILURE; } XMEMCPY(ctx->srp_password, password, XSTRLEN(password) + 1); } return WOLFSSL_SUCCESS; } /** * The modulus passed to wc_SrpSetParams in ssl.c is constant so check * that the requested strength is less than or equal to the size of the * static modulus size. * @param ctx Not used * @param strength Minimum number of bits for the modulus * @return 1 if strength is less than or equal to static modulus * 0 if strength is greater than static modulus */ int wolfSSL_CTX_set_srp_strength(WOLFSSL_CTX *ctx, int strength) { (void)ctx; WOLFSSL_ENTER("wolfSSL_CTX_set_srp_strength"); if (strength > (int)(sizeof(srp_N)*8)) { WOLFSSL_MSG("Bad Parameter"); return WOLFSSL_FAILURE; } return WOLFSSL_SUCCESS; } char* wolfSSL_get_srp_username(WOLFSSL *ssl) { if (ssl && ssl->ctx && ssl->ctx->srp) { return (char*) ssl->ctx->srp->user; } return NULL; } #endif /* WOLFCRYPT_HAVE_SRP && !NO_SHA256 && !WC_NO_RNG */ /* keyblock size in bytes or -1 */ int wolfSSL_get_keyblock_size(WOLFSSL* ssl) { if (ssl == NULL) return WOLFSSL_FATAL_ERROR; return 2 * (ssl->specs.key_size + ssl->specs.iv_size + ssl->specs.hash_size); } #endif /* OPENSSL_EXTRA */ #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) /* store keys returns WOLFSSL_SUCCESS or -1 on error */ int wolfSSL_get_keys(WOLFSSL* ssl, unsigned char** ms, unsigned int* msLen, unsigned char** sr, unsigned int* srLen, unsigned char** cr, unsigned int* crLen) { if (ssl == NULL || ssl->arrays == NULL) return WOLFSSL_FATAL_ERROR; *ms = ssl->arrays->masterSecret; *sr = ssl->arrays->serverRandom; *cr = ssl->arrays->clientRandom; *msLen = SECRET_LEN; *srLen = RAN_LEN; *crLen = RAN_LEN; return WOLFSSL_SUCCESS; } void wolfSSL_set_accept_state(WOLFSSL* ssl) { WOLFSSL_ENTER("wolfSSL_set_accept_state"); if (ssl == NULL) return; if (ssl->options.side == WOLFSSL_CLIENT_END) { #ifdef HAVE_ECC #ifdef WOLFSSL_SMALL_STACK ecc_key* key = NULL; #else ecc_key key[1]; #endif word32 idx = 0; #ifdef WOLFSSL_SMALL_STACK key = (ecc_key*)XMALLOC(sizeof(ecc_key), ssl->heap, DYNAMIC_TYPE_ECC); if (key == NULL) { WOLFSSL_MSG("Error allocating memory for ecc_key"); } #endif if (ssl->options.haveStaticECC && ssl->buffers.key != NULL) { if (wc_ecc_init(key) >= 0) { if (wc_EccPrivateKeyDecode(ssl->buffers.key->buffer, &idx, key, ssl->buffers.key->length) != 0) { ssl->options.haveECDSAsig = 0; ssl->options.haveECC = 0; ssl->options.haveStaticECC = 0; } wc_ecc_free(key); } } #ifdef WOLFSSL_SMALL_STACK XFREE(key, ssl->heap, DYNAMIC_TYPE_ECC); #endif #endif #ifndef NO_DH if (!ssl->options.haveDH && ssl->ctx->haveDH) { ssl->buffers.serverDH_P = ssl->ctx->serverDH_P; ssl->buffers.serverDH_G = ssl->ctx->serverDH_G; ssl->options.haveDH = 1; } #endif } if (InitSSL_Side(ssl, WOLFSSL_SERVER_END) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("Error initializing server side"); } } #endif /* OPENSSL_EXTRA || WOLFSSL_EXTRA || WOLFSSL_WPAS_SMALL */ /* return true if connection established */ int wolfSSL_is_init_finished(WOLFSSL* ssl) { if (ssl == NULL) return 0; if (ssl->options.handShakeState == HANDSHAKE_DONE) return 1; return 0; } #ifdef OPENSSL_EXTRA void wolfSSL_CTX_set_tmp_rsa_callback(WOLFSSL_CTX* ctx, WOLFSSL_RSA*(*f)(WOLFSSL*, int, int)) { /* wolfSSL verifies all these internally */ (void)ctx; (void)f; } void wolfSSL_set_shutdown(WOLFSSL* ssl, int opt) { WOLFSSL_ENTER("wolfSSL_set_shutdown"); if(ssl==NULL) { WOLFSSL_MSG("Shutdown not set. ssl is null"); return; } ssl->options.sentNotify = (opt&WOLFSSL_SENT_SHUTDOWN) > 0; ssl->options.closeNotify = (opt&WOLFSSL_RECEIVED_SHUTDOWN) > 0; } long wolfSSL_CTX_get_options(WOLFSSL_CTX* ctx) { WOLFSSL_ENTER("wolfSSL_CTX_get_options"); WOLFSSL_MSG("wolfSSL options are set through API calls and macros"); if(ctx == NULL) return BAD_FUNC_ARG; return ctx->mask; } #endif static long wolf_set_options(long old_op, long op); long wolfSSL_CTX_set_options(WOLFSSL_CTX* ctx, long opt) { WOLFSSL_ENTER("SSL_CTX_set_options"); if (ctx == NULL) return BAD_FUNC_ARG; ctx->mask = wolf_set_options(ctx->mask, opt); return ctx->mask; } #ifdef OPENSSL_EXTRA long wolfSSL_CTX_clear_options(WOLFSSL_CTX* ctx, long opt) { WOLFSSL_ENTER("SSL_CTX_clear_options"); if(ctx == NULL) return BAD_FUNC_ARG; ctx->mask &= ~opt; return ctx->mask; } int wolfSSL_set_rfd(WOLFSSL* ssl, int rfd) { WOLFSSL_ENTER("SSL_set_rfd"); ssl->rfd = rfd; /* not used directly to allow IO callbacks */ ssl->IOCB_ReadCtx = &ssl->rfd; #ifdef WOLFSSL_DTLS if (ssl->options.dtls) { ssl->IOCB_ReadCtx = &ssl->buffers.dtlsCtx; ssl->buffers.dtlsCtx.rfd = rfd; } #endif return WOLFSSL_SUCCESS; } int wolfSSL_set_wfd(WOLFSSL* ssl, int wfd) { WOLFSSL_ENTER("SSL_set_wfd"); ssl->wfd = wfd; /* not used directly to allow IO callbacks */ ssl->IOCB_WriteCtx = &ssl->wfd; return WOLFSSL_SUCCESS; } #endif /* OPENSSL_EXTRA */ #if !defined(NO_CERTS) && (defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)) #if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) /** * Implemented in a similar way that ngx_ssl_ocsp_validate does it when * SSL_get0_verified_chain is not available. * @param ssl WOLFSSL object to extract certs from * @return Stack of verified certs */ WOLF_STACK_OF(WOLFSSL_X509) *wolfSSL_get0_verified_chain(const WOLFSSL *ssl) { WOLF_STACK_OF(WOLFSSL_X509)* chain = NULL; WOLFSSL_X509_STORE_CTX* storeCtx = NULL; WOLFSSL_X509* peerCert = NULL; WOLFSSL_ENTER("wolfSSL_get0_verified_chain"); if (ssl == NULL || ssl->ctx == NULL) { WOLFSSL_MSG("Bad parameter"); return NULL; } peerCert = wolfSSL_get_peer_certificate((WOLFSSL*)ssl); if (peerCert == NULL) { WOLFSSL_MSG("wolfSSL_get_peer_certificate error"); return NULL; } /* wolfSSL_get_peer_certificate returns a copy. We want the internal * member so that we don't have to worry about free'ing it. We call * wolfSSL_get_peer_certificate so that we don't have to worry about * setting up the internal pointer. */ wolfSSL_X509_free(peerCert); peerCert = (WOLFSSL_X509*)&ssl->peerCert; chain = wolfSSL_get_peer_cert_chain(ssl); if (chain == NULL) { WOLFSSL_MSG("wolfSSL_get_peer_cert_chain error"); return NULL; } storeCtx = wolfSSL_X509_STORE_CTX_new(); if (storeCtx == NULL) { WOLFSSL_MSG("wolfSSL_X509_STORE_CTX_new error"); return NULL; } if (wolfSSL_X509_STORE_CTX_init(storeCtx, SSL_STORE(ssl), peerCert, chain) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("wolfSSL_X509_STORE_CTX_init error"); wolfSSL_X509_STORE_CTX_free(storeCtx); return NULL; } if (wolfSSL_X509_verify_cert(storeCtx) <= 0) { WOLFSSL_MSG("wolfSSL_X509_verify_cert error"); wolfSSL_X509_STORE_CTX_free(storeCtx); return NULL; } wolfSSL_X509_STORE_CTX_free(storeCtx); return chain; } #endif /* SESSION_CERTS && OPENSSL_EXTRA */ WOLFSSL_X509_STORE* wolfSSL_CTX_get_cert_store(WOLFSSL_CTX* ctx) { if (ctx == NULL) { return NULL; } if (ctx->x509_store_pt != NULL) return ctx->x509_store_pt; return &ctx->x509_store; } void wolfSSL_CTX_set_cert_store(WOLFSSL_CTX* ctx, WOLFSSL_X509_STORE* str) { WOLFSSL_ENTER("wolfSSL_CTX_set_cert_store"); if (ctx == NULL || str == NULL || ctx->cm == str->cm) { return; } if (wolfSSL_CertManager_up_ref(str->cm) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("wolfSSL_CertManager_up_ref error"); return; } /* free cert manager if have one */ if (ctx->cm != NULL) { wolfSSL_CertManagerFree(ctx->cm); } ctx->cm = str->cm; ctx->x509_store.cm = str->cm; /* free existing store if it exists */ wolfSSL_X509_STORE_free(ctx->x509_store_pt); ctx->x509_store.cache = str->cache; ctx->x509_store_pt = str; /* take ownership of store and free it with CTX free */ ctx->cm->x509_store_p = ctx->x509_store_pt;/* CTX has onwership and free it with CTX free*/ } int wolfSSL_set0_verify_cert_store(WOLFSSL *ssl, WOLFSSL_X509_STORE* str) { WOLFSSL_ENTER("wolfSSL_set0_verify_cert_store"); if (ssl == NULL || str == NULL) { WOLFSSL_MSG("Bad parameter"); return WOLFSSL_FAILURE; } /* NO-OP when setting existing store */ if (str == SSL_STORE(ssl)) return WOLFSSL_SUCCESS; /* free existing store if it exists */ wolfSSL_X509_STORE_free(ssl->x509_store_pt); if (str == ssl->ctx->x509_store_pt) ssl->x509_store_pt = NULL; /* if setting ctx store then just revert to using that instead */ else ssl->x509_store_pt = str; /* take ownership of store and free it with SSL free */ return WOLFSSL_SUCCESS; } int wolfSSL_set1_verify_cert_store(WOLFSSL *ssl, WOLFSSL_X509_STORE* str) { WOLFSSL_ENTER("wolfSSL_set1_verify_cert_store"); if (ssl == NULL || str == NULL) { WOLFSSL_MSG("Bad parameter"); return WOLFSSL_FAILURE; } /* NO-OP when setting existing store */ if (str == SSL_STORE(ssl)) return WOLFSSL_SUCCESS; if (wolfSSL_X509_STORE_up_ref(str) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("wolfSSL_X509_STORE_up_ref error"); return WOLFSSL_FAILURE; } /* free existing store if it exists */ wolfSSL_X509_STORE_free(ssl->x509_store_pt); if (str == ssl->ctx->x509_store_pt) ssl->x509_store_pt = NULL; /* if setting ctx store then just revert to using that instead */ else ssl->x509_store_pt = str; /* take ownership of store and free it with SSL free */ return WOLFSSL_SUCCESS; } #endif /* !NO_CERTS && (OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL) */ #ifdef WOLFSSL_ENCRYPTED_KEYS void wolfSSL_CTX_set_default_passwd_cb_userdata(WOLFSSL_CTX* ctx, void* userdata) { WOLFSSL_ENTER("SSL_CTX_set_default_passwd_cb_userdata"); if (ctx) ctx->passwd_userdata = userdata; } void wolfSSL_CTX_set_default_passwd_cb(WOLFSSL_CTX* ctx, wc_pem_password_cb* cb) { WOLFSSL_ENTER("SSL_CTX_set_default_passwd_cb"); if (ctx) ctx->passwd_cb = cb; } wc_pem_password_cb* wolfSSL_CTX_get_default_passwd_cb(WOLFSSL_CTX *ctx) { if (ctx == NULL || ctx->passwd_cb == NULL) { return NULL; } return ctx->passwd_cb; } void* wolfSSL_CTX_get_default_passwd_cb_userdata(WOLFSSL_CTX *ctx) { if (ctx == NULL) { return NULL; } return ctx->passwd_userdata; } #endif /* WOLFSSL_ENCRYPTED_KEYS */ #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) int wolfSSL_num_locks(void) { return 0; } void wolfSSL_set_locking_callback(void (*f)(int, int, const char*, int)) { WOLFSSL_ENTER("wolfSSL_set_locking_callback"); if (wc_SetMutexCb(f) != 0) { WOLFSSL_MSG("Error when setting mutex call back"); } } typedef unsigned long (idCb)(void); static idCb* inner_idCb = NULL; unsigned long wolfSSL_thread_id(void) { if (inner_idCb != NULL) { return inner_idCb(); } else { return 0; } } void wolfSSL_set_id_callback(unsigned long (*f)(void)) { inner_idCb = f; } unsigned long wolfSSL_ERR_get_error(void) { WOLFSSL_ENTER("wolfSSL_ERR_get_error"); #ifdef WOLFSSL_HAVE_ERROR_QUEUE #if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) { unsigned long ret = wolfSSL_ERR_peek_error_line_data(NULL, NULL, NULL, NULL); wc_RemoveErrorNode(-1); return ret; } #else { int ret = wc_PullErrorNode(NULL, NULL, NULL); if (ret < 0) { if (ret == BAD_STATE_E) return 0; /* no errors in queue */ WOLFSSL_MSG("Error with pulling error node!"); WOLFSSL_LEAVE("wolfSSL_ERR_get_error", ret); ret = 0 - ret; /* return absolute value of error */ /* panic and try to clear out nodes */ wc_ClearErrorNodes(); } return (unsigned long)ret; } #endif #else return (unsigned long)(0 - NOT_COMPILED_IN); #endif } #ifdef WOLFSSL_HAVE_ERROR_QUEUE #ifndef NO_BIO /* print out and clear all errors */ void wolfSSL_ERR_print_errors(WOLFSSL_BIO* bio) { const char* file = NULL; const char* reason = NULL; int ret; int line = 0; char buf[WOLFSSL_MAX_ERROR_SZ * 2]; WOLFSSL_ENTER("wolfSSL_ERR_print_errors"); if (bio == NULL) { WOLFSSL_MSG("BIO passed in was null"); return; } do { ret = wc_PeekErrorNode(0, &file, &reason, &line); if (ret >= 0) { const char* r = wolfSSL_ERR_reason_error_string(0 - ret); XSNPRINTF(buf, sizeof(buf), "error:%d:wolfSSL library:%s:%s:%d\n", ret, r, file, line); wolfSSL_BIO_write(bio, buf, (int)XSTRLEN(buf)); wc_RemoveErrorNode(0); } } while (ret >= 0); if (wolfSSL_BIO_write(bio, "", 1) != 1) { WOLFSSL_MSG("Issue writing final string terminator"); } } #endif /* !NO_BIO */ #endif /* WOLFSSL_HAVE_ERROR_QUEUE */ #endif /* OPENSSL_EXTRA || HAVE_WEBSERVER */ #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) || \ defined(HAVE_SECRET_CALLBACK) #if !defined(NO_WOLFSSL_SERVER) /* Return the amount of random bytes copied over or error case. * ssl : ssl struct after handshake * out : buffer to hold random bytes * outSz : either 0 (return max buffer sz) or size of out buffer */ size_t wolfSSL_get_server_random(const WOLFSSL *ssl, unsigned char *out, size_t outSz) { size_t size; /* return max size of buffer */ if (outSz == 0) { return RAN_LEN; } if (ssl == NULL || out == NULL) { return 0; } if (ssl->arrays == NULL) { WOLFSSL_MSG("Arrays struct not saved after handshake"); return 0; } if (outSz > RAN_LEN) { size = RAN_LEN; } else { size = outSz; } XMEMCPY(out, ssl->arrays->serverRandom, size); return size; } #endif /* !NO_WOLFSSL_SERVER */ #endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL || HAVE_SECRET_CALLBACK */ #ifdef OPENSSL_EXTRA #if !defined(NO_WOLFSSL_SERVER) /* Used to get the peer ephemeral public key sent during the connection * NOTE: currently wolfSSL_KeepHandshakeResources(WOLFSSL* ssl) must be called * before the ephemeral key is stored. * return WOLFSSL_SUCCESS on success */ int wolfSSL_get_server_tmp_key(const WOLFSSL* ssl, WOLFSSL_EVP_PKEY** pkey) { WOLFSSL_EVP_PKEY* ret = NULL; WOLFSSL_ENTER("wolfSSL_get_server_tmp_key"); if (ssl == NULL || pkey == NULL) { WOLFSSL_MSG("Bad argument passed in"); return WOLFSSL_FAILURE; } #ifdef HAVE_ECC if (ssl->peerEccKey != NULL) { unsigned char* der; const unsigned char* pt; unsigned int derSz = 0; int sz; PRIVATE_KEY_UNLOCK(); if (wc_ecc_export_x963(ssl->peerEccKey, NULL, &derSz) != LENGTH_ONLY_E) { WOLFSSL_MSG("get ecc der size failed"); PRIVATE_KEY_LOCK(); return WOLFSSL_FAILURE; } PRIVATE_KEY_LOCK(); derSz += MAX_SEQ_SZ + (2 * MAX_ALGO_SZ) + MAX_SEQ_SZ + TRAILING_ZERO; der = (unsigned char*)XMALLOC(derSz, ssl->heap, DYNAMIC_TYPE_KEY); if (der == NULL) { WOLFSSL_MSG("Memory error"); return WOLFSSL_FAILURE; } if ((sz = wc_EccPublicKeyToDer(ssl->peerEccKey, der, derSz, 1)) <= 0) { WOLFSSL_MSG("get ecc der failed"); XFREE(der, ssl->heap, DYNAMIC_TYPE_KEY); return WOLFSSL_FAILURE; } pt = der; /* in case pointer gets advanced */ ret = wolfSSL_d2i_PUBKEY(NULL, &pt, sz); XFREE(der, ssl->heap, DYNAMIC_TYPE_KEY); } #endif *pkey = ret; #ifdef HAVE_ECC if (ret != NULL) return WOLFSSL_SUCCESS; else #endif return WOLFSSL_FAILURE; } #endif /* !NO_WOLFSSL_SERVER */ /** * This function checks if any compiled in protocol versions are * left enabled after calls to set_min or set_max API. * @param major The SSL/TLS major version * @return WOLFSSL_SUCCESS on valid settings and WOLFSSL_FAILURE when no * protocol versions are left enabled. */ static int CheckSslMethodVersion(byte major, unsigned long options) { int sanityConfirmed = 0; (void)options; switch (major) { #ifndef NO_TLS case SSLv3_MAJOR: #ifdef WOLFSSL_ALLOW_SSLV3 if (!(options & WOLFSSL_OP_NO_SSLv3)) { sanityConfirmed = 1; } #endif #ifndef NO_OLD_TLS if (!(options & WOLFSSL_OP_NO_TLSv1)) sanityConfirmed = 1; if (!(options & WOLFSSL_OP_NO_TLSv1_1)) sanityConfirmed = 1; #endif #ifndef WOLFSSL_NO_TLS12 if (!(options & WOLFSSL_OP_NO_TLSv1_2)) sanityConfirmed = 1; #endif #ifdef WOLFSSL_TLS13 if (!(options & WOLFSSL_OP_NO_TLSv1_3)) sanityConfirmed = 1; #endif break; #endif #ifdef WOLFSSL_DTLS case DTLS_MAJOR: sanityConfirmed = 1; break; #endif default: WOLFSSL_MSG("Invalid major version"); return WOLFSSL_FAILURE; } if (!sanityConfirmed) { WOLFSSL_MSG("All compiled in TLS versions disabled"); return WOLFSSL_FAILURE; } return WOLFSSL_SUCCESS; } /** * protoVerTbl holds (D)TLS version numbers in ascending order. * Except DTLS versions, the newer version is located in the latter part of * the table. This table is referred by wolfSSL_CTX_set_min_proto_version and * wolfSSL_CTX_set_max_proto_version. */ static const int protoVerTbl[] = { SSL3_VERSION, TLS1_VERSION, TLS1_1_VERSION, TLS1_2_VERSION, TLS1_3_VERSION, DTLS1_VERSION, DTLS1_2_VERSION }; /* number of protocol versions listed in protoVerTbl */ #define NUMBER_OF_PROTOCOLS (sizeof(protoVerTbl)/sizeof(int)) /** * wolfSSL_CTX_set_min_proto_version attempts to set the minimum protocol * version to use by SSL objects created from this WOLFSSL_CTX. * This API guarantees that a version of SSL/TLS lower than specified * here will not be allowed. If the version specified is not compiled in * then this API sets the lowest compiled in protocol version. * This API also accept 0 as version, to set the minimum version automatically. * CheckSslMethodVersion() is called to check if any remaining protocol versions * are enabled. * @param ctx The wolfSSL CONTEXT factory for spawning SSL/TLS objects * @param version Any of the following * * 0 * * SSL3_VERSION * * TLS1_VERSION * * TLS1_1_VERSION * * TLS1_2_VERSION * * TLS1_3_VERSION * * DTLS1_VERSION * * DTLS1_2_VERSION * @return WOLFSSL_SUCCESS on valid settings and WOLFSSL_FAILURE when no * protocol versions are left enabled. */ static int Set_CTX_min_proto_version(WOLFSSL_CTX* ctx, int version) { WOLFSSL_ENTER("wolfSSL_CTX_set_min_proto_version_ex"); if (ctx == NULL) { return WOLFSSL_FAILURE; } switch (version) { #ifndef NO_TLS case SSL3_VERSION: #if defined(WOLFSSL_ALLOW_SSLV3) && !defined(NO_OLD_TLS) ctx->minDowngrade = SSLv3_MINOR; break; #endif case TLS1_VERSION: #ifdef WOLFSSL_ALLOW_TLSV10 ctx->minDowngrade = TLSv1_MINOR; break; #endif case TLS1_1_VERSION: #ifndef NO_OLD_TLS ctx->minDowngrade = TLSv1_1_MINOR; break; #endif case TLS1_2_VERSION: #ifndef WOLFSSL_NO_TLS12 ctx->minDowngrade = TLSv1_2_MINOR; break; #endif case TLS1_3_VERSION: #ifdef WOLFSSL_TLS13 ctx->minDowngrade = TLSv1_3_MINOR; break; #endif #endif #ifdef WOLFSSL_DTLS case DTLS1_VERSION: #ifndef NO_OLD_TLS ctx->minDowngrade = DTLS_MINOR; break; #endif case DTLS1_2_VERSION: ctx->minDowngrade = DTLSv1_2_MINOR; break; #endif default: WOLFSSL_MSG("Unrecognized protocol version or not compiled in"); return WOLFSSL_FAILURE; } switch (version) { #ifndef NO_TLS case TLS1_3_VERSION: wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TLSv1_2); FALL_THROUGH; case TLS1_2_VERSION: wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TLSv1_1); FALL_THROUGH; case TLS1_1_VERSION: wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TLSv1); FALL_THROUGH; case TLS1_VERSION: wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_SSLv3); break; case SSL3_VERSION: case SSL2_VERSION: /* Nothing to do here */ break; #endif #ifdef WOLFSSL_DTLS case DTLS1_VERSION: case DTLS1_2_VERSION: break; #endif default: WOLFSSL_MSG("Unrecognized protocol version or not compiled in"); return WOLFSSL_FAILURE; } return CheckSslMethodVersion(ctx->method->version.major, ctx->mask); } /* Sets the min protocol version allowed with WOLFSSL_CTX * returns WOLFSSL_SUCCESS on success */ int wolfSSL_CTX_set_min_proto_version(WOLFSSL_CTX* ctx, int version) { int ret; int proto = 0; int maxProto = 0; int i; int idx = 0; WOLFSSL_ENTER("wolfSSL_CTX_set_min_proto_version"); if (ctx == NULL) { return WOLFSSL_FAILURE; } if (version != 0) { proto = version; ctx->minProto = 0; /* turn min proto flag off */ for (i = 0; (unsigned)i < NUMBER_OF_PROTOCOLS; i++) { if (protoVerTbl[i] == version) { break; } } } else { /* when 0 is specified as version, try to find out the min version */ for (i = 0; (unsigned)i < NUMBER_OF_PROTOCOLS; i++) { ret = Set_CTX_min_proto_version(ctx, protoVerTbl[i]); if (ret == WOLFSSL_SUCCESS) { proto = protoVerTbl[i]; ctx->minProto = 1; /* turn min proto flag on */ break; } } } /* check case where max > min , if so then clear the NO_* options * i is the index into the table for proto version used, see if the max * proto version index found is smaller */ maxProto = wolfSSL_CTX_get_max_proto_version(ctx); for (idx = 0; (unsigned)idx < NUMBER_OF_PROTOCOLS; idx++) { if (protoVerTbl[idx] == maxProto) { break; } } if (idx < i) { wolfSSL_CTX_clear_options(ctx, WOLFSSL_OP_NO_TLSv1 | WOLFSSL_OP_NO_TLSv1_1 | WOLFSSL_OP_NO_TLSv1_2 | WOLFSSL_OP_NO_TLSv1_3); } ret = Set_CTX_min_proto_version(ctx, proto); return ret; } /** * wolfSSL_CTX_set_max_proto_version attempts to set the maximum protocol * version to use by SSL objects created from this WOLFSSL_CTX. * This API guarantees that a version of SSL/TLS higher than specified * here will not be allowed. If the version specified is not compiled in * then this API sets the highest compiled in protocol version. * This API also accept 0 as version, to set the maximum version automatically. * CheckSslMethodVersion() is called to check if any remaining protocol versions * are enabled. * @param ctx The wolfSSL CONTEXT factory for spawning SSL/TLS objects * @param ver Any of the following * * 0 * * SSL3_VERSION * * TLS1_VERSION * * TLS1_1_VERSION * * TLS1_2_VERSION * * TLS1_3_VERSION * * DTLS1_VERSION * * DTLS1_2_VERSION * @return WOLFSSL_SUCCESS on valid settings and WOLFSSL_FAILURE when no * protocol versions are left enabled. */ static int Set_CTX_max_proto_version(WOLFSSL_CTX* ctx, int ver) { WOLFSSL_ENTER("Set_CTX_max_proto_version"); if (!ctx || !ctx->method) { WOLFSSL_MSG("Bad parameter"); return WOLFSSL_FAILURE; } switch (ver) { case SSL2_VERSION: WOLFSSL_MSG("wolfSSL does not support SSLv2"); return WOLFSSL_FAILURE; #ifndef NO_TLS case SSL3_VERSION: wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TLSv1); FALL_THROUGH; case TLS1_VERSION: wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TLSv1_1); FALL_THROUGH; case TLS1_1_VERSION: wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TLSv1_2); FALL_THROUGH; case TLS1_2_VERSION: wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TLSv1_3); FALL_THROUGH; case TLS1_3_VERSION: /* Nothing to do here */ break; #endif #ifdef WOLFSSL_DTLS case DTLS1_VERSION: case DTLS1_2_VERSION: break; #endif default: WOLFSSL_MSG("Unrecognized protocol version or not compiled in"); return WOLFSSL_FAILURE; } return CheckSslMethodVersion(ctx->method->version.major, ctx->mask); } /* Sets the max protocol version allowed with WOLFSSL_CTX * returns WOLFSSL_SUCCESS on success */ int wolfSSL_CTX_set_max_proto_version(WOLFSSL_CTX* ctx, int version) { int i; int ret = WOLFSSL_FAILURE; int minProto; WOLFSSL_ENTER("wolfSSL_CTX_set_max_proto_version"); if (ctx == NULL) { return ret; } /* clear out flags and reset min protocol version */ minProto = wolfSSL_CTX_get_min_proto_version(ctx); wolfSSL_CTX_clear_options(ctx, WOLFSSL_OP_NO_TLSv1 | WOLFSSL_OP_NO_TLSv1_1 | WOLFSSL_OP_NO_TLSv1_2 | WOLFSSL_OP_NO_TLSv1_3); wolfSSL_CTX_set_min_proto_version(ctx, minProto); if (version != 0) { ctx->maxProto = 0; /* turn max proto flag off */ return Set_CTX_max_proto_version(ctx, version); } /* when 0 is specified as version, try to find out the min version from * the bottom to top of the protoverTbl. */ for (i = NUMBER_OF_PROTOCOLS -1; i >= 0; i--) { ret = Set_CTX_max_proto_version(ctx, protoVerTbl[i]); if (ret == WOLFSSL_SUCCESS) { ctx->maxProto = 1; /* turn max proto flag on */ break; } } return ret; } static int Set_SSL_min_proto_version(WOLFSSL* ssl, int ver) { WOLFSSL_ENTER("Set_SSL_min_proto_version"); if (ssl == NULL) { return WOLFSSL_FAILURE; } switch (ver) { #ifndef NO_TLS case SSL3_VERSION: #if defined(WOLFSSL_ALLOW_SSLV3) && !defined(NO_OLD_TLS) ssl->options.minDowngrade = SSLv3_MINOR; break; #endif case TLS1_VERSION: #ifdef WOLFSSL_ALLOW_TLSV10 ssl->options.minDowngrade = TLSv1_MINOR; break; #endif case TLS1_1_VERSION: #ifndef NO_OLD_TLS ssl->options.minDowngrade = TLSv1_1_MINOR; break; #endif case TLS1_2_VERSION: #ifndef WOLFSSL_NO_TLS12 ssl->options.minDowngrade = TLSv1_2_MINOR; break; #endif case TLS1_3_VERSION: #ifdef WOLFSSL_TLS13 ssl->options.minDowngrade = TLSv1_3_MINOR; break; #endif #endif #ifdef WOLFSSL_DTLS case DTLS1_VERSION: #ifndef NO_OLD_TLS ssl->options.minDowngrade = DTLS_MINOR; break; #endif case DTLS1_2_VERSION: ssl->options.minDowngrade = DTLSv1_2_MINOR; break; #endif default: WOLFSSL_MSG("Unrecognized protocol version or not compiled in"); return WOLFSSL_FAILURE; } switch (ver) { #ifndef NO_TLS case TLS1_3_VERSION: ssl->options.mask |= WOLFSSL_OP_NO_TLSv1_2; FALL_THROUGH; case TLS1_2_VERSION: ssl->options.mask |= WOLFSSL_OP_NO_TLSv1_1; FALL_THROUGH; case TLS1_1_VERSION: ssl->options.mask |= WOLFSSL_OP_NO_TLSv1; FALL_THROUGH; case TLS1_VERSION: ssl->options.mask |= WOLFSSL_OP_NO_SSLv3; break; case SSL3_VERSION: case SSL2_VERSION: /* Nothing to do here */ break; #endif #ifdef WOLFSSL_DTLS case DTLS1_VERSION: case DTLS1_2_VERSION: break; #endif default: WOLFSSL_MSG("Unrecognized protocol version or not compiled in"); return WOLFSSL_FAILURE; } return CheckSslMethodVersion(ssl->version.major, ssl->options.mask); } int wolfSSL_set_min_proto_version(WOLFSSL* ssl, int version) { int i; int ret = WOLFSSL_FAILURE;; WOLFSSL_ENTER("wolfSSL_set_min_proto_version"); if (ssl == NULL) { return WOLFSSL_FAILURE; } if (version != 0) { return Set_SSL_min_proto_version(ssl, version); } /* when 0 is specified as version, try to find out the min version */ for (i= 0; (unsigned)i < NUMBER_OF_PROTOCOLS; i++) { ret = Set_SSL_min_proto_version(ssl, protoVerTbl[i]); if (ret == WOLFSSL_SUCCESS) break; } return ret; } static int Set_SSL_max_proto_version(WOLFSSL* ssl, int ver) { WOLFSSL_ENTER("Set_SSL_max_proto_version"); if (!ssl) { WOLFSSL_MSG("Bad parameter"); return WOLFSSL_FAILURE; } switch (ver) { case SSL2_VERSION: WOLFSSL_MSG("wolfSSL does not support SSLv2"); return WOLFSSL_FAILURE; #ifndef NO_TLS case SSL3_VERSION: ssl->options.mask |= WOLFSSL_OP_NO_TLSv1; FALL_THROUGH; case TLS1_VERSION: ssl->options.mask |= WOLFSSL_OP_NO_TLSv1_1; FALL_THROUGH; case TLS1_1_VERSION: ssl->options.mask |= WOLFSSL_OP_NO_TLSv1_2; FALL_THROUGH; case TLS1_2_VERSION: ssl->options.mask |= WOLFSSL_OP_NO_TLSv1_3; FALL_THROUGH; case TLS1_3_VERSION: /* Nothing to do here */ break; #endif #ifdef WOLFSSL_DTLS case DTLS1_VERSION: case DTLS1_2_VERSION: break; #endif default: WOLFSSL_MSG("Unrecognized protocol version or not compiled in"); return WOLFSSL_FAILURE; } return CheckSslMethodVersion(ssl->version.major, ssl->options.mask); } int wolfSSL_set_max_proto_version(WOLFSSL* ssl, int version) { int i; int ret = WOLFSSL_FAILURE;; WOLFSSL_ENTER("wolfSSL_set_max_proto_version"); if (ssl == NULL) { return WOLFSSL_FAILURE; } if (version != 0) { return Set_SSL_max_proto_version(ssl, version); } /* when 0 is specified as version, try to find out the min version from * the bottom to top of the protoverTbl. */ for (i = NUMBER_OF_PROTOCOLS -1; i >= 0; i--) { ret = Set_SSL_max_proto_version(ssl, protoVerTbl[i]); if (ret == WOLFSSL_SUCCESS) break; } return ret; } static int GetMinProtoVersion(int minDowngrade) { int ret; switch (minDowngrade) { #ifndef NO_OLD_TLS #ifdef WOLFSSL_ALLOW_SSLV3 case SSLv3_MINOR: ret = SSL3_VERSION; break; #endif #ifdef WOLFSSL_ALLOW_TLSV10 case TLSv1_MINOR: ret = TLS1_VERSION; break; #endif case TLSv1_1_MINOR: ret = TLS1_1_VERSION; break; #endif #ifndef WOLFSSL_NO_TLS12 case TLSv1_2_MINOR: ret = TLS1_2_VERSION; break; #endif #ifdef WOLFSSL_TLS13 case TLSv1_3_MINOR: ret = TLS1_3_VERSION; break; #endif default: ret = 0; break; } return ret; } WOLFSSL_API int wolfSSL_CTX_get_min_proto_version(WOLFSSL_CTX* ctx) { int ret = 0; WOLFSSL_ENTER("wolfSSL_CTX_get_min_proto_version"); if (ctx != NULL) { if (ctx->minProto) { ret = 0; } else { ret = GetMinProtoVersion(ctx->minDowngrade); } } else { ret = GetMinProtoVersion(WOLFSSL_MIN_DOWNGRADE); } WOLFSSL_LEAVE("wolfSSL_CTX_get_min_proto_version", ret); return ret; } /* returns the maximum allowed protocol version given the 'options' used * returns WOLFSSL_FATAL_ERROR on no match */ static int GetMaxProtoVersion(long options) { #ifdef WOLFSSL_TLS13 if (!(options & WOLFSSL_OP_NO_TLSv1_3)) return TLS1_3_VERSION; #endif #ifndef WOLFSSL_NO_TLS12 if (!(options & WOLFSSL_OP_NO_TLSv1_2)) return TLS1_2_VERSION; #endif #ifndef NO_OLD_TLS if (!(options & WOLFSSL_OP_NO_TLSv1_1)) return TLS1_1_VERSION; #ifdef WOLFSSL_ALLOW_TLSV10 if (!(options & WOLFSSL_OP_NO_TLSv1)) return TLS1_VERSION; #endif #ifdef WOLFSSL_ALLOW_SSLV3 if (!(options & WOLFSSL_OP_NO_SSLv3)) return SSL3_VERSION; #endif #endif return WOLFSSL_FATAL_ERROR; } /* returns the maximum protocol version for 'ctx' */ int wolfSSL_CTX_get_max_proto_version(WOLFSSL_CTX* ctx) { int ret = 0; long options = 0; /* default to nothing set */ WOLFSSL_ENTER("wolfSSL_CTX_get_max_proto_version"); if (ctx != NULL) { options = wolfSSL_CTX_get_options(ctx); } if ((ctx != NULL) && ctx->maxProto) { ret = 0; } else { ret = GetMaxProtoVersion(options); } WOLFSSL_LEAVE("wolfSSL_CTX_get_max_proto_version", ret); if (ret == WOLFSSL_FATAL_ERROR) { WOLFSSL_MSG("Error getting max proto version"); ret = 0; /* setting ret to 0 to match compat return */ } return ret; } #endif /* OPENSSL_EXTRA */ #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) || \ defined(HAVE_SECRET_CALLBACK) #if !defined(NO_WOLFSSL_CLIENT) /* Return the amount of random bytes copied over or error case. * ssl : ssl struct after handshake * out : buffer to hold random bytes * outSz : either 0 (return max buffer sz) or size of out buffer */ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out, size_t outSz) { size_t size; /* return max size of buffer */ if (outSz == 0) { return RAN_LEN; } if (ssl == NULL || out == NULL) { return 0; } if (ssl->arrays == NULL) { WOLFSSL_MSG("Arrays struct not saved after handshake"); return 0; } if (outSz > RAN_LEN) { size = RAN_LEN; } else { size = outSz; } XMEMCPY(out, ssl->arrays->clientRandom, size); return size; } #endif /* !NO_WOLFSSL_CLIENT */ #endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL || HAVE_SECRET_CALLBACK */ #ifdef OPENSSL_EXTRA unsigned long wolfSSLeay(void) { return SSLEAY_VERSION_NUMBER; } unsigned long wolfSSL_OpenSSL_version_num(void) { return OPENSSL_VERSION_NUMBER; } const char* wolfSSLeay_version(int type) { (void)type; #if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000L return wolfSSL_OpenSSL_version(type); #else return wolfSSL_OpenSSL_version(); #endif } #ifndef NO_MD5 int wolfSSL_MD5_Init(WOLFSSL_MD5_CTX* md5) { int ret; typedef char md5_test[sizeof(MD5_CTX) >= sizeof(wc_Md5) ? 1 : -1]; (void)sizeof(md5_test); WOLFSSL_ENTER("MD5_Init"); ret = wc_InitMd5((wc_Md5*)md5); /* return 1 on success, 0 otherwise */ if (ret == 0) return 1; return 0; } int wolfSSL_MD5_Update(WOLFSSL_MD5_CTX* md5, const void* input, unsigned long sz) { int ret; WOLFSSL_ENTER("wolfSSL_MD5_Update"); ret = wc_Md5Update((wc_Md5*)md5, (const byte*)input, (word32)sz); /* return 1 on success, 0 otherwise */ if (ret == 0) return 1; return 0; } int wolfSSL_MD5_Final(byte* output, WOLFSSL_MD5_CTX* md5) { int ret; WOLFSSL_ENTER("MD5_Final"); ret = wc_Md5Final((wc_Md5*)md5, output); /* have to actually free the resources (if any) here, because the * OpenSSL API doesn't include SHA*_Free(). */ wc_Md5Free((wc_Md5*)md5); /* return 1 on success, 0 otherwise */ if (ret == 0) return 1; return 0; } /* Apply MD5 transformation to the data */ int wolfSSL_MD5_Transform(WOLFSSL_MD5_CTX* md5, const unsigned char* data) { int ret; WOLFSSL_ENTER("MD5_Transform"); /* sanity check */ if (md5 == NULL || data == NULL) { return 0; } #if defined(BIG_ENDIAN_ORDER) { ByteReverseWords((word32*)data, (word32*)data, WC_MD5_BLOCK_SIZE); } #endif ret = wc_Md5Transform((wc_Md5*)md5, data); /* return 1 on success, 0 otherwise */ if (ret == 0) return 1; else return 0; } unsigned char *wolfSSL_MD5(const unsigned char* data, size_t len, unsigned char* hash) { static unsigned char out[WC_MD5_DIGEST_SIZE]; WOLFSSL_ENTER("wolfSSL_MD5"); if (hash == NULL) hash = out; if (wc_Md5Hash(data, (word32)len, hash) != 0) { WOLFSSL_MSG("wc_Md5Hash error"); return NULL; } return hash; } #endif /* !NO_MD5 */ #ifndef NO_SHA int wolfSSL_SHA_Init(WOLFSSL_SHA_CTX* sha) { int ret; typedef char sha_test[sizeof(SHA_CTX) >= sizeof(wc_Sha) ? 1 : -1]; (void)sizeof(sha_test); WOLFSSL_ENTER("SHA_Init"); ret = wc_InitSha((wc_Sha*)sha); /* return 1 on success, 0 otherwise */ if (ret == 0) return 1; return 0; } int wolfSSL_SHA_Update(WOLFSSL_SHA_CTX* sha, const void* input, unsigned long sz) { int ret; WOLFSSL_ENTER("SHA_Update"); ret = wc_ShaUpdate((wc_Sha*)sha, (const byte*)input, (word32)sz); /* return 1 on success, 0 otherwise */ if (ret == 0) return 1; return 0; } int wolfSSL_SHA_Final(byte* output, WOLFSSL_SHA_CTX* sha) { int ret; WOLFSSL_ENTER("SHA_Final"); ret = wc_ShaFinal((wc_Sha*)sha, output); /* have to actually free the resources (if any) here, because the * OpenSSL API doesn't include SHA*_Free(). */ wc_ShaFree((wc_Sha*)sha); /* return 1 on success, 0 otherwise */ if (ret == 0) return 1; return 0; } #if defined(OPENSSL_EXTRA) #if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || \ (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION > 2))) /* Apply SHA1 transformation to the data */ int wolfSSL_SHA_Transform(WOLFSSL_SHA_CTX* sha, const unsigned char* data) { int ret; WOLFSSL_ENTER("SHA_Transform"); /* sanity check */ if (sha == NULL || data == NULL) { return 0; } #if defined(LITTLE_ENDIAN_ORDER) { ByteReverseWords((word32*)data, (word32*)data, WC_SHA_BLOCK_SIZE); } #endif ret = wc_ShaTransform((wc_Sha*)sha, data); /* return 1 on success, 0 otherwise */ if (ret == 0) return 1; else return 0; } #endif #endif int wolfSSL_SHA1_Init(WOLFSSL_SHA_CTX* sha) { WOLFSSL_ENTER("SHA1_Init"); return SHA_Init(sha); } int wolfSSL_SHA1_Update(WOLFSSL_SHA_CTX* sha, const void* input, unsigned long sz) { WOLFSSL_ENTER("SHA1_Update"); return SHA_Update(sha, input, sz); } int wolfSSL_SHA1_Final(byte* output, WOLFSSL_SHA_CTX* sha) { WOLFSSL_ENTER("SHA1_Final"); return SHA_Final(output, sha); } #if defined(OPENSSL_EXTRA) #if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || \ (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION > 2))) /* Apply SHA1 transformation to the data */ int wolfSSL_SHA1_Transform(WOLFSSL_SHA_CTX* sha, const unsigned char* data) { WOLFSSL_ENTER("SHA1_Transform"); return (wolfSSL_SHA_Transform(sha, data)); } #endif #endif #endif /* !NO_SHA */ #ifdef WOLFSSL_SHA224 int wolfSSL_SHA224_Init(WOLFSSL_SHA224_CTX* sha) { int ret; typedef char sha_test[sizeof(SHA224_CTX) >= sizeof(wc_Sha224) ? 1 : -1]; (void)sizeof(sha_test); WOLFSSL_ENTER("SHA224_Init"); ret = wc_InitSha224((wc_Sha224*)sha); /* return 1 on success, 0 otherwise */ if (ret == 0) return 1; return 0; } int wolfSSL_SHA224_Update(WOLFSSL_SHA224_CTX* sha, const void* input, unsigned long sz) { int ret; WOLFSSL_ENTER("SHA224_Update"); ret = wc_Sha224Update((wc_Sha224*)sha, (const byte*)input, (word32)sz); /* return 1 on success, 0 otherwise */ if (ret == 0) return 1; return 0; } int wolfSSL_SHA224_Final(byte* output, WOLFSSL_SHA224_CTX* sha) { int ret; WOLFSSL_ENTER("SHA224_Final"); ret = wc_Sha224Final((wc_Sha224*)sha, output); /* have to actually free the resources (if any) here, because the * OpenSSL API doesn't include SHA*_Free(). */ wc_Sha224Free((wc_Sha224*)sha); /* return 1 on success, 0 otherwise */ if (ret == 0) return 1; return 0; } #endif /* WOLFSSL_SHA224 */ int wolfSSL_SHA256_Init(WOLFSSL_SHA256_CTX* sha256) { int ret; typedef char sha_test[sizeof(SHA256_CTX) >= sizeof(wc_Sha256) ? 1 : -1]; (void)sizeof(sha_test); WOLFSSL_ENTER("SHA256_Init"); ret = wc_InitSha256((wc_Sha256*)sha256); /* return 1 on success, 0 otherwise */ if (ret == 0) return 1; return 0; } int wolfSSL_SHA256_Update(WOLFSSL_SHA256_CTX* sha, const void* input, unsigned long sz) { int ret; WOLFSSL_ENTER("SHA256_Update"); ret = wc_Sha256Update((wc_Sha256*)sha, (const byte*)input, (word32)sz); /* return 1 on success, 0 otherwise */ if (ret == 0) return 1; return 0; } int wolfSSL_SHA256_Final(byte* output, WOLFSSL_SHA256_CTX* sha) { int ret; WOLFSSL_ENTER("SHA256_Final"); ret = wc_Sha256Final((wc_Sha256*)sha, output); /* have to actually free the resources (if any) here, because the * OpenSSL API doesn't include SHA*_Free(). */ wc_Sha256Free((wc_Sha256*)sha); /* return 1 on success, 0 otherwise */ if (ret == 0) return 1; return 0; } #if defined(OPENSSL_EXTRA) #if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || \ (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION > 2))) && \ !defined(WOLFSSL_DEVCRYPTO_HASH) && !defined(WOLFSSL_AFALG_HASH) /* Apply SHA256 transformation to the data */ int wolfSSL_SHA256_Transform(WOLFSSL_SHA256_CTX* sha256, const unsigned char* data) { int ret; WOLFSSL_ENTER("SHA256_Transform"); /* sanity check */ if (sha256 == NULL || data == NULL) { return 0; } #if defined(LITTLE_ENDIAN_ORDER) { ByteReverseWords((word32*)data, (word32*)data, WC_SHA256_BLOCK_SIZE); } #endif ret = wc_Sha256Transform((wc_Sha256*)sha256, data); /* return 1 on success, 0 otherwise */ if (ret == 0) return 1; else return 0; } #endif #endif #ifdef WOLFSSL_SHA384 int wolfSSL_SHA384_Init(WOLFSSL_SHA384_CTX* sha) { int ret; typedef char sha_test[sizeof(SHA384_CTX) >= sizeof(wc_Sha384) ? 1 : -1]; (void)sizeof(sha_test); WOLFSSL_ENTER("SHA384_Init"); ret = wc_InitSha384((wc_Sha384*)sha); /* return 1 on success, 0 otherwise */ if (ret == 0) return 1; return 0; } int wolfSSL_SHA384_Update(WOLFSSL_SHA384_CTX* sha, const void* input, unsigned long sz) { int ret; WOLFSSL_ENTER("SHA384_Update"); ret = wc_Sha384Update((wc_Sha384*)sha, (const byte*)input, (word32)sz); /* return 1 on success, 0 otherwise */ if (ret == 0) return 1; return 0; } int wolfSSL_SHA384_Final(byte* output, WOLFSSL_SHA384_CTX* sha) { int ret; WOLFSSL_ENTER("SHA384_Final"); ret = wc_Sha384Final((wc_Sha384*)sha, output); /* have to actually free the resources (if any) here, because the * OpenSSL API doesn't include SHA*_Free(). */ wc_Sha384Free((wc_Sha384*)sha); /* return 1 on success, 0 otherwise */ if (ret == 0) return 1; return 0; } #endif /* WOLFSSL_SHA384 */ #ifdef WOLFSSL_SHA512 int wolfSSL_SHA512_Init(WOLFSSL_SHA512_CTX* sha) { int ret; typedef char sha_test[sizeof(SHA512_CTX) >= sizeof(wc_Sha512) ? 1 : -1]; (void)sizeof(sha_test); WOLFSSL_ENTER("SHA512_Init"); ret = wc_InitSha512((wc_Sha512*)sha); /* return 1 on success, 0 otherwise */ if (ret == 0) return 1; return 0; } int wolfSSL_SHA512_Update(WOLFSSL_SHA512_CTX* sha, const void* input, unsigned long sz) { int ret; WOLFSSL_ENTER("SHA512_Update"); ret = wc_Sha512Update((wc_Sha512*)sha, (const byte*)input, (word32)sz); /* return 1 on success, 0 otherwise */ if (ret == 0) return 1; return 0; } int wolfSSL_SHA512_Final(byte* output, WOLFSSL_SHA512_CTX* sha) { int ret; WOLFSSL_ENTER("SHA512_Final"); ret = wc_Sha512Final((wc_Sha512*)sha, output); /* have to actually free the resources (if any) here, because the * OpenSSL API doesn't include SHA*_Free(). */ wc_Sha512Free((wc_Sha512*)sha); /* return 1 on success, 0 otherwise */ if (ret == 0) return 1; return 0; } #if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || \ (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION > 2))) /* Apply SHA512 transformation to the data */ int wolfSSL_SHA512_Transform(WOLFSSL_SHA512_CTX* sha512, const unsigned char* data) { int ret; WOLFSSL_ENTER("SHA512_Transform"); /* sanity check */ if (sha512 == NULL || data == NULL) { return WOLFSSL_FAILURE; } ret = wc_Sha512Transform((wc_Sha512*)sha512, data); /* return 1 on success, 0 otherwise */ if (ret == 0) return WOLFSSL_SUCCESS; else return WOLFSSL_FAILURE; } #endif /* !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \ (HAVE_FIPS_VERSION > 2)) */ #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) #if !defined(WOLFSSL_NOSHA512_224) int wolfSSL_SHA512_224_Init(WOLFSSL_SHA512_224_CTX* sha) { int ret; WOLFSSL_ENTER("wolfSSL_SHA512_224_Init"); ret = wc_InitSha512_224((wc_Sha512*)sha); /* return WOLFSSL_SUCCESS on success, WOLFSSL_FAILURE otherwise */ if (ret == 0) return WOLFSSL_SUCCESS; return WOLFSSL_FAILURE; } int wolfSSL_SHA512_224_Update(WOLFSSL_SHA512_224_CTX* sha, const void* input, unsigned long sz) { int ret; WOLFSSL_ENTER("wolfSSL_SHA512_224_Update"); ret = wc_Sha512_224Update((wc_Sha512*)sha, (const byte*)input, (word32)sz); /* return WOLFSSL_SUCCESS on success, WOLFSSL_FAILURE otherwise */ if (ret == 0) return WOLFSSL_SUCCESS; return WOLFSSL_FAILURE; } int wolfSSL_SHA512_224_Final(byte* output, WOLFSSL_SHA512_224_CTX* sha) { int ret; WOLFSSL_ENTER("wolfSSL_SHA512_224_Final"); ret = wc_Sha512_224Final((wc_Sha512*)sha, output); /* return WOLFSSL_SUCCESS on success, WOLFSSL_FAILURE otherwise */ if (ret == 0) return WOLFSSL_SUCCESS; return WOLFSSL_FAILURE; } #if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || \ (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION > 2))) /* Apply SHA512 transformation to the data */ int wolfSSL_SHA512_224_Transform(WOLFSSL_SHA512_CTX* sha512, const unsigned char* data) { int ret; WOLFSSL_ENTER("SHA512_224_Transform"); /* sanity check */ if (sha512 == NULL || data == NULL) { return WOLFSSL_FAILURE; } ret = wc_Sha512_224Transform((wc_Sha512*)sha512, data); /* return 1 on success, 0 otherwise */ if (ret == 0) return WOLFSSL_SUCCESS; else return WOLFSSL_FAILURE; } #endif /* !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \ (HAVE_FIPS_VERSION > 2)) */ #endif /* !WOLFSSL_NOSHA512_224 */ #if !defined(WOLFSSL_NOSHA512_256) int wolfSSL_SHA512_256_Init(WOLFSSL_SHA512_256_CTX* sha) { int ret; WOLFSSL_ENTER("wolfSSL_SHA512_256_Init"); ret = wc_InitSha512_256((wc_Sha512*)sha); /* return WOLFSSL_SUCCESS on success, WOLFSSL_FAILURE otherwise */ if (ret == 0) return WOLFSSL_SUCCESS; return WOLFSSL_FAILURE; } int wolfSSL_SHA512_256_Update(WOLFSSL_SHA512_256_CTX* sha, const void* input, unsigned long sz) { int ret; WOLFSSL_ENTER("wolfSSL_SHA512_256_Update"); ret = wc_Sha512_256Update((wc_Sha512*)sha, (const byte*)input, (word32)sz); /* return WOLFSSL_SUCCESS on success, WOLFSSL_FAILURE otherwise */ if (ret == 0) return WOLFSSL_SUCCESS; return WOLFSSL_FAILURE; } int wolfSSL_SHA512_256_Final(byte* output, WOLFSSL_SHA512_256_CTX* sha) { int ret; WOLFSSL_ENTER("wolfSSL_SHA512_256_Final"); ret = wc_Sha512_256Final((wc_Sha512*)sha, output); /* return WOLFSSL_SUCCESS on success, 0 otherwise */ if (ret == 0) return WOLFSSL_SUCCESS; return WOLFSSL_FAILURE; } #if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || \ (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION > 2))) /* Apply SHA512 transformation to the data */ int wolfSSL_SHA512_256_Transform(WOLFSSL_SHA512_CTX* sha512, const unsigned char* data) { int ret; WOLFSSL_ENTER("SHA512_256_Transform"); /* sanity check */ if (sha512 == NULL || data == NULL) { return WOLFSSL_FAILURE; } ret = wc_Sha512_256Transform((wc_Sha512*)sha512, data); /* return 1 on success, 0 otherwise */ if (ret == 0) return WOLFSSL_SUCCESS; else return WOLFSSL_FAILURE; } #endif /* !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \ (HAVE_FIPS_VERSION > 2)) */ #endif /* !WOLFSSL_NOSHA512_256 */ #endif /* !HAVE_FIPS && !HAVE_SELFTEST */ #endif /* WOLFSSL_SHA512 */ #ifdef WOLFSSL_SHA3 #ifndef WOLFSSL_NOSHA3_224 int wolfSSL_SHA3_224_Init(WOLFSSL_SHA3_224_CTX* sha) { int ret; typedef char sha_test[sizeof(SHA3_224_CTX) >= sizeof(wc_Sha3) ? 1 : -1]; (void)sizeof(sha_test); WOLFSSL_ENTER("SHA3_224_Init"); ret = wc_InitSha3_224((wc_Sha3*)sha, NULL, INVALID_DEVID); /* return 1 on success, 0 otherwise */ if (ret == 0) return 1; return 0; } int wolfSSL_SHA3_224_Update(WOLFSSL_SHA3_224_CTX* sha, const void* input, unsigned long sz) { int ret; WOLFSSL_ENTER("SHA3_224_Update"); ret = wc_Sha3_224_Update((wc_Sha3*)sha, (const byte*)input, (word32)sz); /* return 1 on success, 0 otherwise */ if (ret == 0) return 1; return 0; } int wolfSSL_SHA3_224_Final(byte* output, WOLFSSL_SHA3_224_CTX* sha) { int ret; WOLFSSL_ENTER("SHA3_224_Final"); ret = wc_Sha3_224_Final((wc_Sha3*)sha, output); /* have to actually free the resources (if any) here, because the * OpenSSL API doesn't include SHA*_Free(). */ wc_Sha3_224_Free((wc_Sha3*)sha); /* return 1 on success, 0 otherwise */ if (ret == 0) return 1; return 0; } #endif /* WOLFSSL_NOSHA3_224 */ #ifndef WOLFSSL_NOSHA3_256 int wolfSSL_SHA3_256_Init(WOLFSSL_SHA3_256_CTX* sha3_256) { int ret; typedef char sha_test[sizeof(SHA3_256_CTX) >= sizeof(wc_Sha3) ? 1 : -1]; (void)sizeof(sha_test); WOLFSSL_ENTER("SHA3_256_Init"); ret = wc_InitSha3_256((wc_Sha3*)sha3_256, NULL, INVALID_DEVID); /* return 1 on success, 0 otherwise */ if (ret == 0) return 1; return 0; } int wolfSSL_SHA3_256_Update(WOLFSSL_SHA3_256_CTX* sha, const void* input, unsigned long sz) { int ret; WOLFSSL_ENTER("SHA3_256_Update"); ret = wc_Sha3_256_Update((wc_Sha3*)sha, (const byte*)input, (word32)sz); /* return 1 on success, 0 otherwise */ if (ret == 0) return 1; return 0; } int wolfSSL_SHA3_256_Final(byte* output, WOLFSSL_SHA3_256_CTX* sha) { int ret; WOLFSSL_ENTER("SHA3_256_Final"); ret = wc_Sha3_256_Final((wc_Sha3*)sha, output); /* have to actually free the resources (if any) here, because the * OpenSSL API doesn't include SHA*_Free(). */ wc_Sha3_256_Free((wc_Sha3*)sha); /* return 1 on success, 0 otherwise */ if (ret == 0) return 1; return 0; } #endif /* WOLFSSL_NOSHA3_256 */ int wolfSSL_SHA3_384_Init(WOLFSSL_SHA3_384_CTX* sha) { int ret; typedef char sha_test[sizeof(SHA3_384_CTX) >= sizeof(wc_Sha3) ? 1 : -1]; (void)sizeof(sha_test); WOLFSSL_ENTER("SHA3_384_Init"); ret = wc_InitSha3_384((wc_Sha3*)sha, NULL, INVALID_DEVID); /* return 1 on success, 0 otherwise */ if (ret == 0) return 1; return 0; } int wolfSSL_SHA3_384_Update(WOLFSSL_SHA3_384_CTX* sha, const void* input, unsigned long sz) { int ret; WOLFSSL_ENTER("SHA3_384_Update"); ret = wc_Sha3_384_Update((wc_Sha3*)sha, (const byte*)input, (word32)sz); /* return 1 on success, 0 otherwise */ if (ret == 0) return 1; return 0; } int wolfSSL_SHA3_384_Final(byte* output, WOLFSSL_SHA3_384_CTX* sha) { int ret; WOLFSSL_ENTER("SHA3_384_Final"); ret = wc_Sha3_384_Final((wc_Sha3*)sha, output); /* have to actually free the resources (if any) here, because the * OpenSSL API doesn't include SHA*_Free(). */ wc_Sha3_384_Free((wc_Sha3*)sha); /* return 1 on success, 0 otherwise */ if (ret == 0) return 1; return 0; } #ifndef WOLFSSL_NOSHA3_512 int wolfSSL_SHA3_512_Init(WOLFSSL_SHA3_512_CTX* sha) { int ret; typedef char sha_test[sizeof(SHA3_512_CTX) >= sizeof(wc_Sha3) ? 1 : -1]; (void)sizeof(sha_test); WOLFSSL_ENTER("SHA3_512_Init"); ret = wc_InitSha3_512((wc_Sha3*)sha, NULL, INVALID_DEVID); /* return 1 on success, 0 otherwise */ if (ret == 0) return 1; return 0; } int wolfSSL_SHA3_512_Update(WOLFSSL_SHA3_512_CTX* sha, const void* input, unsigned long sz) { int ret; WOLFSSL_ENTER("SHA3_512_Update"); ret = wc_Sha3_512_Update((wc_Sha3*)sha, (const byte*)input, (word32)sz); /* return 1 on success, 0 otherwise */ if (ret == 0) return 1; return 0; } int wolfSSL_SHA3_512_Final(byte* output, WOLFSSL_SHA3_512_CTX* sha) { int ret; WOLFSSL_ENTER("SHA3_512_Final"); ret = wc_Sha3_512_Final((wc_Sha3*)sha, output); /* have to actually free the resources (if any) here, because the * OpenSSL API doesn't include SHA*_Free(). */ wc_Sha3_512_Free((wc_Sha3*)sha); /* return 1 on success, 0 otherwise */ if (ret == 0) return 1; return 0; } #endif /* WOLFSSL_NOSHA3_512 */ #endif /* WOLFSSL_SHA3 */ unsigned char* wolfSSL_HMAC(const WOLFSSL_EVP_MD* evp_md, const void* key, int key_len, const unsigned char* d, int n, unsigned char* md, unsigned int* md_len) { int type; int mdlen; unsigned char* ret = NULL; #ifdef WOLFSSL_SMALL_STACK Hmac* hmac = NULL; #else Hmac hmac[1]; #endif void* heap = NULL; WOLFSSL_ENTER("wolfSSL_HMAC"); if (!md) { WOLFSSL_MSG("Static buffer not supported, pass in md buffer"); return NULL; /* no static buffer support */ } #ifndef NO_MD5 if (XSTRCMP(evp_md, "MD5") == 0) { type = WC_MD5; mdlen = WC_MD5_DIGEST_SIZE; } else #endif #ifdef WOLFSSL_SHA224 if (XSTRCMP(evp_md, "SHA224") == 0) { type = WC_SHA224; mdlen = WC_SHA224_DIGEST_SIZE; } else #endif #ifndef NO_SHA256 if (XSTRCMP(evp_md, "SHA256") == 0) { type = WC_SHA256; mdlen = WC_SHA256_DIGEST_SIZE; } else #endif #ifdef WOLFSSL_SHA384 if (XSTRCMP(evp_md, "SHA384") == 0) { type = WC_SHA384; mdlen = WC_SHA384_DIGEST_SIZE; } else #endif #ifdef WOLFSSL_SHA512 if (XSTRCMP(evp_md, "SHA512") == 0) { type = WC_SHA512; mdlen = WC_SHA512_DIGEST_SIZE; } else #endif #ifdef WOLFSSL_SHA3 #ifndef WOLFSSL_NOSHA3_224 if (XSTRCMP(evp_md, "SHA3_224") == 0) { type = WC_SHA3_224; mdlen = WC_SHA3_224_DIGEST_SIZE; } else #endif #ifndef WOLFSSL_NOSHA3_256 if (XSTRCMP(evp_md, "SHA3_256") == 0) { type = WC_SHA3_256; mdlen = WC_SHA3_256_DIGEST_SIZE; } else #endif if (XSTRCMP(evp_md, "SHA3_384") == 0) { type = WC_SHA3_384; mdlen = WC_SHA3_384_DIGEST_SIZE; } else #ifndef WOLFSSL_NOSHA3_512 if (XSTRCMP(evp_md, "SHA3_512") == 0) { type = WC_SHA3_512; mdlen = WC_SHA3_512_DIGEST_SIZE; } else #endif #endif #ifndef NO_SHA if (XSTRCMP(evp_md, "SHA") == 0) { type = WC_SHA; mdlen = WC_SHA_DIGEST_SIZE; } else #endif { return NULL; } #ifdef WOLFSSL_SMALL_STACK hmac = (Hmac*)XMALLOC(sizeof(Hmac), heap, DYNAMIC_TYPE_HMAC); if (hmac == NULL) return NULL; #endif if (wc_HmacInit(hmac, heap, INVALID_DEVID) == 0) { if (wc_HmacSetKey(hmac, type, (const byte*)key, key_len) == 0) { if (wc_HmacUpdate(hmac, d, n) == 0) { if (wc_HmacFinal(hmac, md) == 0) { if (md_len) *md_len = mdlen; ret = md; } } } wc_HmacFree(hmac); } #ifdef WOLFSSL_SMALL_STACK XFREE(hmac, heap, DYNAMIC_TYPE_HMAC); #endif (void)evp_md; return ret; } #ifndef NO_DES3 /* 0 on ok */ int wolfSSL_DES_key_sched(WOLFSSL_const_DES_cblock* key, WOLFSSL_DES_key_schedule* schedule) { WOLFSSL_ENTER("wolfSSL_DES_key_sched"); if (key == NULL || schedule == NULL) { WOLFSSL_MSG("Null argument passed in"); } else { XMEMCPY(schedule, key, sizeof(WOLFSSL_const_DES_cblock)); } return 0; } /* intended to behave similar to Kerberos mit_des_cbc_cksum * return the last 4 bytes of cipher text */ WOLFSSL_DES_LONG wolfSSL_DES_cbc_cksum(const unsigned char* in, WOLFSSL_DES_cblock* out, long length, WOLFSSL_DES_key_schedule* sc, WOLFSSL_const_DES_cblock* iv) { WOLFSSL_DES_LONG ret; unsigned char* tmp; unsigned char* data = (unsigned char*)in; long dataSz = length; byte dynamicFlag = 0; /* when padding the buffer created needs free'd */ WOLFSSL_ENTER("wolfSSL_DES_cbc_cksum"); if (in == NULL || out == NULL || sc == NULL || iv == NULL) { WOLFSSL_MSG("Bad argument passed in"); return 0; } /* if input length is not a multiple of DES_BLOCK_SIZE pad with 0s */ if (dataSz % DES_BLOCK_SIZE) { dataSz += DES_BLOCK_SIZE - (dataSz % DES_BLOCK_SIZE); data = (unsigned char*)XMALLOC(dataSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (data == NULL) { WOLFSSL_MSG("Issue creating temporary buffer"); return 0; } dynamicFlag = 1; /* set to free buffer at end */ XMEMCPY(data, in, length); XMEMSET(data + length, 0, dataSz - length); /* padding */ } tmp = (unsigned char*)XMALLOC(dataSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (tmp == NULL) { WOLFSSL_MSG("Issue creating temporary buffer"); if (dynamicFlag == 1) { XFREE(data, NULL, DYNAMIC_TYPE_TMP_BUFFER); } return 0; } wolfSSL_DES_cbc_encrypt(data, tmp, dataSz, sc, (WOLFSSL_DES_cblock*)iv, 1); XMEMCPY((unsigned char*)out, tmp + (dataSz - DES_BLOCK_SIZE), DES_BLOCK_SIZE); ret = (((*((unsigned char*)out + 4) & 0xFF) << 24)| ((*((unsigned char*)out + 5) & 0xFF) << 16)| ((*((unsigned char*)out + 6) & 0xFF) << 8) | (*((unsigned char*)out + 7) & 0xFF)); XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (dynamicFlag == 1) { XFREE(data, NULL, DYNAMIC_TYPE_TMP_BUFFER); } return ret; } void wolfSSL_DES_cbc_encrypt(const unsigned char* input, unsigned char* output, long length, WOLFSSL_DES_key_schedule* schedule, WOLFSSL_DES_cblock* ivec, int enc) { Des myDes; byte lastblock[DES_BLOCK_SIZE]; int lb_sz; long blk; WOLFSSL_ENTER("DES_cbc_encrypt"); /* OpenSSL compat, no ret */ if (wc_Des_SetKey(&myDes, (const byte*)schedule, (const byte*)ivec, !enc) != 0) { WOLFSSL_MSG("wc_Des_SetKey return error."); return; } lb_sz = length%DES_BLOCK_SIZE; blk = length/DES_BLOCK_SIZE; if (enc == DES_ENCRYPT){ wc_Des_CbcEncrypt(&myDes, output, input, (word32)blk*DES_BLOCK_SIZE); if(lb_sz){ XMEMSET(lastblock, 0, DES_BLOCK_SIZE); XMEMCPY(lastblock, input+length-lb_sz, lb_sz); wc_Des_CbcEncrypt(&myDes, output+blk*DES_BLOCK_SIZE, lastblock, (word32)DES_BLOCK_SIZE); } } else { wc_Des_CbcDecrypt(&myDes, output, input, (word32)blk*DES_BLOCK_SIZE); if(lb_sz){ wc_Des_CbcDecrypt(&myDes, lastblock, input+length-lb_sz, (word32)DES_BLOCK_SIZE); XMEMCPY(output+length-lb_sz, lastblock, lb_sz); } } } /* WOLFSSL_DES_key_schedule is a unsigned char array of size 8 */ void wolfSSL_DES_ede3_cbc_encrypt(const unsigned char* input, unsigned char* output, long sz, WOLFSSL_DES_key_schedule* ks1, WOLFSSL_DES_key_schedule* ks2, WOLFSSL_DES_key_schedule* ks3, WOLFSSL_DES_cblock* ivec, int enc) { int ret; Des3 des; byte key[24];/* EDE uses 24 size key */ byte lastblock[DES_BLOCK_SIZE]; int lb_sz; long blk; WOLFSSL_ENTER("wolfSSL_DES_ede3_cbc_encrypt"); XMEMSET(key, 0, sizeof(key)); XMEMCPY(key, *ks1, DES_BLOCK_SIZE); XMEMCPY(&key[DES_BLOCK_SIZE], *ks2, DES_BLOCK_SIZE); XMEMCPY(&key[DES_BLOCK_SIZE * 2], *ks3, DES_BLOCK_SIZE); lb_sz = sz%DES_BLOCK_SIZE; blk = sz/DES_BLOCK_SIZE; /* OpenSSL compat, no ret */ (void)wc_Des3Init(&des, NULL, INVALID_DEVID); if (enc == DES_ENCRYPT) { if (wc_Des3_SetKey(&des, key, (const byte*)ivec, DES_ENCRYPTION) == 0) { ret = wc_Des3_CbcEncrypt(&des, output, input, (word32)blk*DES_BLOCK_SIZE); #if defined(WOLFSSL_ASYNC_CRYPT) ret = wc_AsyncWait(ret, &des.asyncDev, WC_ASYNC_FLAG_NONE); #endif (void)ret; /* ignore return codes for processing */ if(lb_sz){ XMEMSET(lastblock, 0, DES_BLOCK_SIZE); XMEMCPY(lastblock, input+sz-lb_sz, lb_sz); ret = wc_Des3_CbcEncrypt(&des, output+blk*DES_BLOCK_SIZE, lastblock, (word32)DES_BLOCK_SIZE); #if defined(WOLFSSL_ASYNC_CRYPT) ret = wc_AsyncWait(ret, &des.asyncDev, WC_ASYNC_FLAG_NONE); #endif (void)ret; /* ignore return codes for processing */ } } } else { if (wc_Des3_SetKey(&des, key, (const byte*)ivec, DES_DECRYPTION) == 0) { ret = wc_Des3_CbcDecrypt(&des, output, input, (word32)blk*DES_BLOCK_SIZE); #if defined(WOLFSSL_ASYNC_CRYPT) ret = wc_AsyncWait(ret, &des.asyncDev, WC_ASYNC_FLAG_NONE); #endif (void)ret; /* ignore return codes for processing */ if(lb_sz){ ret = wc_Des3_CbcDecrypt(&des, lastblock, input+sz-lb_sz, (word32)DES_BLOCK_SIZE); #if defined(WOLFSSL_ASYNC_CRYPT) ret = wc_AsyncWait(ret, &des.asyncDev, WC_ASYNC_FLAG_NONE); #endif (void)ret; /* ignore return codes for processing */ XMEMCPY(output+sz-lb_sz, lastblock, lb_sz); } } } wc_Des3Free(&des); } /* correctly sets ivec for next call */ void wolfSSL_DES_ncbc_encrypt(const unsigned char* input, unsigned char* output, long length, WOLFSSL_DES_key_schedule* schedule, WOLFSSL_DES_cblock* ivec, int enc) { Des myDes; byte lastblock[DES_BLOCK_SIZE]; int lb_sz; long idx = length; long blk; WOLFSSL_ENTER("DES_ncbc_encrypt"); /* OpenSSL compat, no ret */ if (wc_Des_SetKey(&myDes, (const byte*)schedule, (const byte*)ivec, !enc) != 0) { WOLFSSL_MSG("wc_Des_SetKey return error."); return; } lb_sz = length%DES_BLOCK_SIZE; blk = length/DES_BLOCK_SIZE; idx -= sizeof(DES_cblock); if (lb_sz) { idx += DES_BLOCK_SIZE - lb_sz; } if (enc == DES_ENCRYPT){ wc_Des_CbcEncrypt(&myDes, output, input, (word32)blk * DES_BLOCK_SIZE); if (lb_sz){ XMEMSET(lastblock, 0, DES_BLOCK_SIZE); XMEMCPY(lastblock, input+length-lb_sz, lb_sz); wc_Des_CbcEncrypt(&myDes, output + blk * DES_BLOCK_SIZE, lastblock, (word32)DES_BLOCK_SIZE); } XMEMCPY(ivec, output + idx, sizeof(DES_cblock)); } else { WOLFSSL_DES_cblock tmp; XMEMCPY(tmp, input + idx, sizeof(DES_cblock)); wc_Des_CbcDecrypt(&myDes, output, input, (word32)blk * DES_BLOCK_SIZE); if (lb_sz){ wc_Des_CbcDecrypt(&myDes, lastblock, input + length - lb_sz, (word32)DES_BLOCK_SIZE); XMEMCPY(output+length-lb_sz, lastblock, lb_sz); } XMEMCPY(ivec, tmp, sizeof(WOLFSSL_DES_cblock)); } } #endif /* NO_DES3 */ void wolfSSL_ERR_free_strings(void) { /* handled internally */ } void wolfSSL_cleanup_all_ex_data(void) { /* nothing to do here */ } #endif /* OPENSSL_EXTRA */ #if defined(OPENSSL_EXTRA) || defined(DEBUG_WOLFSSL_VERBOSE) void wolfSSL_ERR_clear_error(void) { WOLFSSL_ENTER("wolfSSL_ERR_clear_error"); wc_ClearErrorNodes(); } #endif #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) int wolfSSL_clear(WOLFSSL* ssl) { WOLFSSL_ENTER("wolfSSL_clear"); if (ssl == NULL) { return WOLFSSL_FAILURE; } if (!ssl->options.handShakeDone) { /* Only reset the session if we didn't complete a handshake */ wolfSSL_SESSION_free(ssl->session); ssl->session = wolfSSL_NewSession(ssl->heap); if (ssl->session == NULL) { return WOLFSSL_FAILURE; } } 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; ssl->options.connectState = CONNECT_BEGIN; ssl->options.acceptState = ACCEPT_BEGIN; ssl->options.handShakeState = NULL_STATE; ssl->options.handShakeDone = 0; ssl->options.processReply = 0; /* doProcessInit */ ssl->keys.encryptionOn = 0; XMEMSET(&ssl->msgsReceived, 0, sizeof(ssl->msgsReceived)); if (ssl->hsHashes) (void)InitHandshakeHashes(ssl); #ifdef KEEP_PEER_CERT FreeX509(&ssl->peerCert); InitX509(&ssl->peerCert, 0, ssl->heap); #endif return WOLFSSL_SUCCESS; } #endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */ #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) long wolfSSL_CTX_set_mode(WOLFSSL_CTX* ctx, long mode) { /* WOLFSSL_MODE_ACCEPT_MOVING_WRITE_BUFFER is wolfSSL default mode */ WOLFSSL_ENTER("SSL_CTX_set_mode"); switch(mode) { case SSL_MODE_ENABLE_PARTIAL_WRITE: ctx->partialWrite = 1; break; #if defined(OPENSSL_ALL) || defined(WOLFSSL_QT) case SSL_MODE_RELEASE_BUFFERS: WOLFSSL_MSG("SSL_MODE_RELEASE_BUFFERS not implemented."); break; #endif case SSL_MODE_AUTO_RETRY: ctx->autoRetry = 1; break; default: WOLFSSL_MSG("Mode Not Implemented"); } /* SSL_MODE_AUTO_RETRY * Should not return -1 with renegotiation on read/write */ return mode; } long wolfSSL_CTX_clear_mode(WOLFSSL_CTX* ctx, long mode) { /* WOLFSSL_MODE_ACCEPT_MOVING_WRITE_BUFFER is wolfSSL default mode */ WOLFSSL_ENTER("SSL_CTX_set_mode"); switch(mode) { case SSL_MODE_ENABLE_PARTIAL_WRITE: ctx->partialWrite = 0; break; #if defined(OPENSSL_ALL) || defined(WOLFSSL_QT) case SSL_MODE_RELEASE_BUFFERS: WOLFSSL_MSG("SSL_MODE_RELEASE_BUFFERS not implemented."); break; #endif case SSL_MODE_AUTO_RETRY: ctx->autoRetry = 0; break; default: WOLFSSL_MSG("Mode Not Implemented"); } /* SSL_MODE_AUTO_RETRY * Should not return -1 with renegotiation on read/write */ return 0; } #endif #ifdef OPENSSL_EXTRA #ifndef NO_WOLFSSL_STUB long wolfSSL_SSL_get_mode(WOLFSSL* ssl) { /* TODO: */ (void)ssl; WOLFSSL_STUB("SSL_get_mode"); return 0; } #endif #ifndef NO_WOLFSSL_STUB long wolfSSL_CTX_get_mode(WOLFSSL_CTX* ctx) { /* TODO: */ (void)ctx; WOLFSSL_STUB("SSL_CTX_get_mode"); return 0; } #endif #ifndef NO_WOLFSSL_STUB void wolfSSL_CTX_set_default_read_ahead(WOLFSSL_CTX* ctx, int m) { /* TODO: maybe? */ (void)ctx; (void)m; WOLFSSL_STUB("SSL_CTX_set_default_read_ahead"); } #endif /* Storing app session context id, this value is inherited by WOLFSSL * objects created from WOLFSSL_CTX. Any session that is imported with a * different session context id will be rejected. * * ctx structure to set context in * sid_ctx value of context to set * sid_ctx_len length of sid_ctx buffer * * Returns WOLFSSL_SUCCESS in success case and SSL_FAILURE when failing */ int wolfSSL_CTX_set_session_id_context(WOLFSSL_CTX* ctx, const unsigned char* sid_ctx, unsigned int sid_ctx_len) { WOLFSSL_ENTER("SSL_CTX_set_session_id_context"); /* No application specific context needed for wolfSSL */ if (sid_ctx_len > ID_LEN || ctx == NULL || sid_ctx == NULL) { return SSL_FAILURE; } XMEMCPY(ctx->sessionCtx, sid_ctx, sid_ctx_len); ctx->sessionCtxSz = (byte)sid_ctx_len; return WOLFSSL_SUCCESS; } /* Storing app session context id. Any session that is imported with a * different session context id will be rejected. * * ssl structure to set context in * id value of context to set * len length of sid_ctx buffer * * Returns WOLFSSL_SUCCESS in success case and SSL_FAILURE when failing */ int wolfSSL_set_session_id_context(WOLFSSL* ssl, const unsigned char* id, unsigned int len) { WOLFSSL_ENTER("wolfSSL_set_session_id_context"); if (len > ID_LEN || ssl == NULL || id == NULL) { return SSL_FAILURE; } XMEMCPY(ssl->sessionCtx, id, len); ssl->sessionCtxSz = (byte)len; return WOLFSSL_SUCCESS; } long wolfSSL_CTX_sess_get_cache_size(WOLFSSL_CTX* ctx) { (void)ctx; #ifndef NO_SESSION_CACHE return (long)(SESSIONS_PER_ROW * SESSION_ROWS); #else return 0; #endif } /* returns the unsigned error value and increments the pointer into the * error queue. * * file pointer to file name * line gets set to line number of error when not NULL */ unsigned long wolfSSL_ERR_get_error_line(const char** file, int* line) { #ifdef WOLFSSL_HAVE_ERROR_QUEUE int ret = wc_PullErrorNode(file, NULL, line); if (ret < 0) { if (ret == BAD_STATE_E) return 0; /* no errors in queue */ WOLFSSL_MSG("Issue getting error node"); WOLFSSL_LEAVE("wolfSSL_ERR_get_error_line", ret); ret = 0 - ret; /* return absolute value of error */ /* panic and try to clear out nodes */ wc_ClearErrorNodes(); } return (unsigned long)ret; #else (void)file; (void)line; return 0; #endif } #if (defined(DEBUG_WOLFSSL) || defined(OPENSSL_EXTRA)) && \ (!defined(_WIN32) && !defined(NO_ERROR_QUEUE)) static const char WOLFSSL_SYS_ACCEPT_T[] = "accept"; static const char WOLFSSL_SYS_BIND_T[] = "bind"; static const char WOLFSSL_SYS_CONNECT_T[] = "connect"; static const char WOLFSSL_SYS_FOPEN_T[] = "fopen"; static const char WOLFSSL_SYS_FREAD_T[] = "fread"; static const char WOLFSSL_SYS_GETADDRINFO_T[] = "getaddrinfo"; static const char WOLFSSL_SYS_GETSOCKOPT_T[] = "getsockopt"; static const char WOLFSSL_SYS_GETSOCKNAME_T[] = "getsockname"; static const char WOLFSSL_SYS_GETHOSTBYNAME_T[] = "gethostbyname"; static const char WOLFSSL_SYS_GETNAMEINFO_T[] = "getnameinfo"; static const char WOLFSSL_SYS_GETSERVBYNAME_T[] = "getservbyname"; static const char WOLFSSL_SYS_IOCTLSOCKET_T[] = "ioctlsocket"; static const char WOLFSSL_SYS_LISTEN_T[] = "listen"; static const char WOLFSSL_SYS_OPENDIR_T[] = "opendir"; static const char WOLFSSL_SYS_SETSOCKOPT_T[] = "setsockopt"; static const char WOLFSSL_SYS_SOCKET_T[] = "socket"; /* switch with int mapped to function name for compatibility */ static const char* wolfSSL_ERR_sys_func(int fun) { switch (fun) { case WOLFSSL_SYS_ACCEPT: return WOLFSSL_SYS_ACCEPT_T; case WOLFSSL_SYS_BIND: return WOLFSSL_SYS_BIND_T; case WOLFSSL_SYS_CONNECT: return WOLFSSL_SYS_CONNECT_T; case WOLFSSL_SYS_FOPEN: return WOLFSSL_SYS_FOPEN_T; case WOLFSSL_SYS_FREAD: return WOLFSSL_SYS_FREAD_T; case WOLFSSL_SYS_GETADDRINFO: return WOLFSSL_SYS_GETADDRINFO_T; case WOLFSSL_SYS_GETSOCKOPT: return WOLFSSL_SYS_GETSOCKOPT_T; case WOLFSSL_SYS_GETSOCKNAME: return WOLFSSL_SYS_GETSOCKNAME_T; case WOLFSSL_SYS_GETHOSTBYNAME: return WOLFSSL_SYS_GETHOSTBYNAME_T; case WOLFSSL_SYS_GETNAMEINFO: return WOLFSSL_SYS_GETNAMEINFO_T; case WOLFSSL_SYS_GETSERVBYNAME: return WOLFSSL_SYS_GETSERVBYNAME_T; case WOLFSSL_SYS_IOCTLSOCKET: return WOLFSSL_SYS_IOCTLSOCKET_T; case WOLFSSL_SYS_LISTEN: return WOLFSSL_SYS_LISTEN_T; case WOLFSSL_SYS_OPENDIR: return WOLFSSL_SYS_OPENDIR_T; case WOLFSSL_SYS_SETSOCKOPT: return WOLFSSL_SYS_SETSOCKOPT_T; case WOLFSSL_SYS_SOCKET: return WOLFSSL_SYS_SOCKET_T; default: return "NULL"; } } #endif /* DEBUG_WOLFSSL */ /* @TODO when having an error queue this needs to push to the queue */ void wolfSSL_ERR_put_error(int lib, int fun, int err, const char* file, int line) { WOLFSSL_ENTER("wolfSSL_ERR_put_error"); #if !defined(DEBUG_WOLFSSL) && !defined(OPENSSL_EXTRA) (void)fun; (void)err; (void)file; (void)line; WOLFSSL_MSG("Not compiled in debug mode"); #elif defined(OPENSSL_EXTRA) && \ (defined(_WIN32) || defined(NO_ERROR_QUEUE)) (void)fun; (void)file; (void)line; WOLFSSL_ERROR(err); #else WOLFSSL_ERROR_LINE(err, wolfSSL_ERR_sys_func(fun), (unsigned int)line, file, NULL); #endif (void)lib; } /* Similar to wolfSSL_ERR_get_error_line but takes in a flags argument for * more flexibility. * * file output pointer to file where error happened * line output to line number of error * data output data. Is a string if ERR_TXT_STRING flag is used * flags output format of output * * Returns the error value or 0 if no errors are in the queue */ unsigned long wolfSSL_ERR_get_error_line_data(const char** file, int* line, const char** data, int *flags) { #ifdef WOLFSSL_HAVE_ERROR_QUEUE int ret; WOLFSSL_ENTER("wolfSSL_ERR_get_error_line_data"); if (flags != NULL) *flags = ERR_TXT_STRING; /* Clear the flags */ ret = wc_PullErrorNode(file, data, line); if (ret < 0) { if (ret == BAD_STATE_E) return 0; /* no errors in queue */ WOLFSSL_MSG("Error with pulling error node!"); WOLFSSL_LEAVE("wolfSSL_ERR_get_error_line_data", ret); ret = 0 - ret; /* return absolute value of error */ /* panic and try to clear out nodes */ wc_ClearErrorNodes(); } return (unsigned long)ret; #else WOLFSSL_ENTER("wolfSSL_ERR_get_error_line_data"); WOLFSSL_MSG("Error queue turned off, can not get error line"); (void)file; (void)line; (void)data; (void)flags; return 0; #endif } #endif /* OPENSSL_EXTRA */ #if (defined(KEEP_PEER_CERT) && defined(SESSION_CERTS)) || \ (defined(OPENSSL_EXTRA) && defined(SESSION_CERTS)) /* Decode the X509 DER encoded certificate into a WOLFSSL_X509 object. * * x509 WOLFSSL_X509 object to decode into. * in X509 DER data. * len Length of the X509 DER data. * returns the new certificate on success, otherwise NULL. */ static int DecodeToX509(WOLFSSL_X509* x509, const byte* in, int len) { int ret; #ifdef WOLFSSL_SMALL_STACK DecodedCert* cert; #else DecodedCert cert[1]; #endif if (x509 == NULL || in == NULL || len <= 0) return BAD_FUNC_ARG; #ifdef WOLFSSL_SMALL_STACK cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, DYNAMIC_TYPE_DCERT); if (cert == NULL) return MEMORY_E; #endif /* Create a DecodedCert object and copy fields into WOLFSSL_X509 object. */ InitDecodedCert(cert, (byte*)in, len, NULL); if ((ret = ParseCertRelative(cert, CERT_TYPE, 0, NULL)) == 0) { /* Check if x509 was not previously initialized by wolfSSL_X509_new() */ if (x509->dynamicMemory != TRUE) InitX509(x509, 0, NULL); ret = CopyDecodedToX509(x509, cert); FreeDecodedCert(cert); } #ifdef WOLFSSL_SMALL_STACK XFREE(cert, NULL, DYNAMIC_TYPE_DCERT); #endif return ret; } #endif /* (KEEP_PEER_CERT & SESSION_CERTS) || (OPENSSL_EXTRA & SESSION_CERTS) */ #ifdef KEEP_PEER_CERT WOLFSSL_ABI WOLFSSL_X509* wolfSSL_get_peer_certificate(WOLFSSL* ssl) { WOLFSSL_X509* ret = NULL; WOLFSSL_ENTER("SSL_get_peer_certificate"); if (ssl != NULL) { if (ssl->peerCert.issuer.sz) ret = wolfSSL_X509_dup(&ssl->peerCert); #ifdef SESSION_CERTS else if (ssl->session->chain.count > 0) { if (DecodeToX509(&ssl->peerCert, ssl->session->chain.certs[0].buffer, ssl->session->chain.certs[0].length) == 0) { ret = wolfSSL_X509_dup(&ssl->peerCert); } } #endif } WOLFSSL_LEAVE("SSL_get_peer_certificate", ret != NULL); return ret; } #endif /* KEEP_PEER_CERT */ #if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) /* Return stack of peer certs. * Caller does not need to free return. The stack is Free'd when WOLFSSL* ssl is. */ WOLF_STACK_OF(WOLFSSL_X509)* wolfSSL_get_peer_cert_chain(const WOLFSSL* ssl) { WOLFSSL_ENTER("wolfSSL_get_peer_cert_chain"); if (ssl == NULL) return NULL; /* Try to populate if NULL or empty */ if (ssl->peerCertChain == NULL || wolfSSL_sk_X509_num(ssl->peerCertChain) == 0) wolfSSL_set_peer_cert_chain((WOLFSSL*) ssl); return ssl->peerCertChain; } #ifndef WOLFSSL_QT static int x509GetIssuerFromCM(WOLFSSL_X509 **issuer, WOLFSSL_CERT_MANAGER* cm, WOLFSSL_X509 *x); /** * Recursively push the issuer CA chain onto the stack * @param cm The cert manager that is queried for the issuer * @param x This cert's issuer will be queried in cm * @param sk The issuer is pushed onto this stack * @return WOLFSSL_SUCCESS on success * WOLFSSL_FAILURE on no issuer found * WOLFSSL_FATAL_ERROR on a fatal error */ static int PushCAx509Chain(WOLFSSL_CERT_MANAGER* cm, WOLFSSL_X509 *x, WOLFSSL_STACK* sk) { WOLFSSL_X509* issuer[MAX_CHAIN_DEPTH]; int i; int push = 1; int ret = WOLFSSL_SUCCESS; for (i = 0; i < MAX_CHAIN_DEPTH; i++) { if (x509GetIssuerFromCM(&issuer[i], cm, x) != WOLFSSL_SUCCESS) break; x = issuer[i]; } if (i == 0) /* No further chain found */ return WOLFSSL_FAILURE; i--; for (; i >= 0; i--) { if (push) { if (wolfSSL_sk_X509_push(sk, issuer[i]) != WOLFSSL_SUCCESS) { wolfSSL_X509_free(issuer[i]); ret = WOLFSSL_FATAL_ERROR; push = 0; /* Free the rest of the unpushed certs */ } } else { wolfSSL_X509_free(issuer[i]); } } return ret; } #endif /* !WOLFSSL_QT */ /* Builds up and creates a stack of peer certificates for ssl->peerCertChain based off of the ssl session chain. Attempts to place CA certificates at the bottom of the stack. Returns stack of WOLFSSL_X509 certs or NULL on failure */ WOLF_STACK_OF(WOLFSSL_X509)* wolfSSL_set_peer_cert_chain(WOLFSSL* ssl) { WOLFSSL_STACK* sk; WOLFSSL_X509* x509; int i = 0; int ret; WOLFSSL_ENTER("wolfSSL_set_peer_cert_chain"); if ((ssl == NULL) || (ssl->session->chain.count == 0)) return NULL; sk = wolfSSL_sk_X509_new(); i = ssl->session->chain.count-1; for (; i >= 0; i--) { x509 = wolfSSL_X509_new(); if (x509 == NULL) { WOLFSSL_MSG("Error Creating X509"); wolfSSL_sk_X509_pop_free(sk, NULL); return NULL; } ret = DecodeToX509(x509, ssl->session->chain.certs[i].buffer, ssl->session->chain.certs[i].length); #if !defined(WOLFSSL_QT) if (ret == 0 && i == ssl->session->chain.count-1) { /* On the last element in the chain try to add the CA chain * first if we have one for this cert */ if (PushCAx509Chain(SSL_CM(ssl), x509, sk) == WOLFSSL_FATAL_ERROR) { ret = WOLFSSL_FATAL_ERROR; } } #endif if (ret != 0 || wolfSSL_sk_X509_push(sk, x509) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("Error decoding cert"); wolfSSL_X509_free(x509); wolfSSL_sk_X509_pop_free(sk, NULL); return NULL; } } if (sk == NULL) { WOLFSSL_MSG("Null session chain"); } #if defined(OPENSSL_ALL) else if (ssl->options.side == WOLFSSL_SERVER_END) { /* to be compliant with openssl first element is kept as peer cert on server side.*/ wolfSSL_sk_X509_shift(sk); } #endif if (ssl->peerCertChain != NULL) wolfSSL_sk_X509_pop_free(ssl->peerCertChain, NULL); /* This is Free'd when ssl is Free'd */ ssl->peerCertChain = sk; return sk; } #endif /* SESSION_CERTS && OPENSSL_EXTRA */ #ifndef NO_CERTS #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) /* create a generic wolfSSL stack node * returns a new WOLFSSL_STACK structure on success */ WOLFSSL_STACK* wolfSSL_sk_new_node(void* heap) { WOLFSSL_STACK* sk; WOLFSSL_ENTER("wolfSSL_sk_new_node"); sk = (WOLFSSL_STACK*)XMALLOC(sizeof(WOLFSSL_STACK), heap, DYNAMIC_TYPE_OPENSSL); if (sk != NULL) { XMEMSET(sk, 0, sizeof(*sk)); sk->heap = heap; } return sk; } /* free's node but does not free internal data such as in->data.x509 */ void wolfSSL_sk_free_node(WOLFSSL_STACK* in) { if (in != NULL) { XFREE(in, in->heap, DYNAMIC_TYPE_OPENSSL); } } /* pushes node "in" onto "stack" and returns pointer to the new stack on success * also handles internal "num" for number of nodes on stack * return WOLFSSL_SUCCESS on success */ int wolfSSL_sk_push_node(WOLFSSL_STACK** stack, WOLFSSL_STACK* in) { if (stack == NULL || in == NULL) { return WOLFSSL_FAILURE; } if (*stack == NULL) { in->num = 1; *stack = in; return WOLFSSL_SUCCESS; } in->num = (*stack)->num + 1; in->next = *stack; *stack = in; return WOLFSSL_SUCCESS; } #if defined(OPENSSL_ALL) || defined(WOLFSSL_QT) static WC_INLINE int compare_WOLFSSL_CIPHER( WOLFSSL_CIPHER *a, WOLFSSL_CIPHER *b) { if ((a->cipherSuite0 == b->cipherSuite0) && (a->cipherSuite == b->cipherSuite) && (a->ssl == b->ssl) && (XMEMCMP(a->description, b->description, sizeof a->description) == 0) && (a->offset == b->offset) && (a->in_stack == b->in_stack) && (a->bits == b->bits)) return 0; else return -1; } #endif /* OPENSSL_ALL || WOLFSSL_QT */ /* return 1 on success 0 on fail */ int wolfSSL_sk_push(WOLFSSL_STACK* sk, const void *data) { WOLFSSL_STACK* node; #if defined(OPENSSL_ALL) || defined(WOLFSSL_QT) WOLFSSL_CIPHER ciph; #endif WOLFSSL_ENTER("wolfSSL_sk_push"); if (!sk) { return WOLFSSL_FAILURE; } /* Check if empty data */ switch (sk->type) { case STACK_TYPE_CIPHER: #if defined(OPENSSL_ALL) || defined(WOLFSSL_QT) /* check if entire struct is zero */ XMEMSET(&ciph, 0, sizeof(WOLFSSL_CIPHER)); if (compare_WOLFSSL_CIPHER(&sk->data.cipher, &ciph) == 0) { sk->data.cipher = *(WOLFSSL_CIPHER*)data; sk->num = 1; if (sk->hash_fn) { sk->hash = sk->hash_fn(&sk->data.cipher); } return WOLFSSL_SUCCESS; } break; #endif case STACK_TYPE_X509: case STACK_TYPE_GEN_NAME: case STACK_TYPE_BIO: case STACK_TYPE_OBJ: case STACK_TYPE_STRING: case STACK_TYPE_ACCESS_DESCRIPTION: case STACK_TYPE_X509_EXT: case STACK_TYPE_X509_REQ_ATTR: case STACK_TYPE_NULL: case STACK_TYPE_X509_NAME: case STACK_TYPE_X509_NAME_ENTRY: case STACK_TYPE_CONF_VALUE: case STACK_TYPE_X509_INFO: case STACK_TYPE_BY_DIR_entry: case STACK_TYPE_BY_DIR_hash: case STACK_TYPE_X509_OBJ: case STACK_TYPE_DIST_POINT: case STACK_TYPE_X509_CRL: default: /* All other types are pointers */ if (!sk->data.generic) { sk->data.generic = (void*)data; sk->num = 1; #ifdef OPENSSL_ALL if (sk->hash_fn) { sk->hash = sk->hash_fn(sk->data.generic); } #endif return WOLFSSL_SUCCESS; } break; } /* stack already has value(s) create a new node and add more */ node = wolfSSL_sk_new_node(sk->heap); if (!node) { WOLFSSL_MSG("Memory error"); return WOLFSSL_FAILURE; } /* push new x509 onto head of stack */ node->next = sk->next; node->type = sk->type; sk->next = node; sk->num += 1; #ifdef OPENSSL_ALL node->comp = sk->comp; node->hash_fn = sk->hash_fn; node->hash = sk->hash; sk->hash = 0; #endif switch (sk->type) { case STACK_TYPE_CIPHER: #if defined(OPENSSL_ALL) || defined(WOLFSSL_QT) node->data.cipher = sk->data.cipher; sk->data.cipher = *(WOLFSSL_CIPHER*)data; if (sk->hash_fn) { sk->hash = sk->hash_fn(&sk->data.cipher); } break; #endif case STACK_TYPE_X509: case STACK_TYPE_GEN_NAME: case STACK_TYPE_BIO: case STACK_TYPE_OBJ: case STACK_TYPE_STRING: case STACK_TYPE_ACCESS_DESCRIPTION: case STACK_TYPE_X509_EXT: case STACK_TYPE_X509_REQ_ATTR: case STACK_TYPE_NULL: case STACK_TYPE_X509_NAME: case STACK_TYPE_X509_NAME_ENTRY: case STACK_TYPE_CONF_VALUE: case STACK_TYPE_X509_INFO: case STACK_TYPE_BY_DIR_entry: case STACK_TYPE_BY_DIR_hash: case STACK_TYPE_X509_OBJ: case STACK_TYPE_DIST_POINT: case STACK_TYPE_X509_CRL: default: /* All other types are pointers */ node->data.generic = sk->data.generic; sk->data.generic = (void*)data; #ifdef OPENSSL_ALL if (sk->hash_fn) { sk->hash = sk->hash_fn(sk->data.generic); } #endif break; } return WOLFSSL_SUCCESS; } #endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */ #ifdef OPENSSL_EXTRA /* returns the node at index "idx", NULL if not found */ WOLFSSL_STACK* wolfSSL_sk_get_node(WOLFSSL_STACK* sk, int idx) { int i; WOLFSSL_STACK* ret = NULL; WOLFSSL_STACK* current; current = sk; for (i = 0; i <= idx && current != NULL; i++) { if (i == idx) { ret = current; break; } current = current->next; } return ret; } #endif /* OPENSSL_EXTRA */ #ifdef OPENSSL_EXTRA #if defined(OPENSSL_ALL) void *wolfSSL_lh_retrieve(WOLFSSL_STACK *sk, void *data) { unsigned long hash; WOLFSSL_ENTER("wolfSSL_lh_retrieve"); if (!sk || !data) { WOLFSSL_MSG("Bad parameters"); return NULL; } if (!sk->hash_fn) { WOLFSSL_MSG("No hash function defined"); return NULL; } hash = sk->hash_fn(data); while (sk) { /* Calc hash if not done so yet */ if (!sk->hash) { switch (sk->type) { case STACK_TYPE_CIPHER: sk->hash = sk->hash_fn(&sk->data.cipher); break; case STACK_TYPE_X509: case STACK_TYPE_GEN_NAME: case STACK_TYPE_BIO: case STACK_TYPE_OBJ: case STACK_TYPE_STRING: case STACK_TYPE_ACCESS_DESCRIPTION: case STACK_TYPE_X509_EXT: case STACK_TYPE_X509_REQ_ATTR: case STACK_TYPE_NULL: case STACK_TYPE_X509_NAME: case STACK_TYPE_X509_NAME_ENTRY: case STACK_TYPE_CONF_VALUE: case STACK_TYPE_X509_INFO: case STACK_TYPE_BY_DIR_entry: case STACK_TYPE_BY_DIR_hash: case STACK_TYPE_X509_OBJ: case STACK_TYPE_DIST_POINT: case STACK_TYPE_X509_CRL: default: sk->hash = sk->hash_fn(sk->data.generic); break; } } if (sk->hash == hash) { switch (sk->type) { case STACK_TYPE_CIPHER: return &sk->data.cipher; case STACK_TYPE_X509: case STACK_TYPE_GEN_NAME: case STACK_TYPE_BIO: case STACK_TYPE_OBJ: case STACK_TYPE_STRING: case STACK_TYPE_ACCESS_DESCRIPTION: case STACK_TYPE_X509_EXT: case STACK_TYPE_X509_REQ_ATTR: case STACK_TYPE_NULL: case STACK_TYPE_X509_NAME: case STACK_TYPE_X509_NAME_ENTRY: case STACK_TYPE_CONF_VALUE: case STACK_TYPE_X509_INFO: case STACK_TYPE_BY_DIR_entry: case STACK_TYPE_BY_DIR_hash: case STACK_TYPE_X509_OBJ: case STACK_TYPE_DIST_POINT: case STACK_TYPE_X509_CRL: default: return sk->data.generic; } } sk = sk->next; } return NULL; } #endif /* OPENSSL_ALL */ #endif /* OPENSSL_EXTRA */ /* OPENSSL_EXTRA is needed for wolfSSL_X509_d21 function KEEP_OUR_CERT is to insure ability for returning ssl certificate */ #if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && \ defined(KEEP_OUR_CERT) WOLFSSL_X509* wolfSSL_get_certificate(WOLFSSL* ssl) { if (ssl == NULL) { return NULL; } if (ssl->buffers.weOwnCert) { if (ssl->ourCert == NULL) { if (ssl->buffers.certificate == NULL) { WOLFSSL_MSG("Certificate buffer not set!"); return NULL; } #ifndef WOLFSSL_X509_STORE_CERTS ssl->ourCert = wolfSSL_X509_d2i(NULL, ssl->buffers.certificate->buffer, ssl->buffers.certificate->length); #endif } return ssl->ourCert; } else { /* if cert not owned get parent ctx cert or return null */ if (ssl->ctx) { if (ssl->ctx->ourCert == NULL) { if (ssl->ctx->certificate == NULL) { WOLFSSL_MSG("Ctx Certificate buffer not set!"); return NULL; } #ifndef WOLFSSL_X509_STORE_CERTS ssl->ctx->ourCert = wolfSSL_X509_d2i(NULL, ssl->ctx->certificate->buffer, ssl->ctx->certificate->length); #endif ssl->ctx->ownOurCert = 1; } return ssl->ctx->ourCert; } } return NULL; } WOLFSSL_X509* wolfSSL_CTX_get0_certificate(WOLFSSL_CTX* ctx) { if (ctx) { if (ctx->ourCert == NULL) { if (ctx->certificate == NULL) { WOLFSSL_MSG("Ctx Certificate buffer not set!"); return NULL; } #ifndef WOLFSSL_X509_STORE_CERTS ctx->ourCert = wolfSSL_X509_d2i(NULL, ctx->certificate->buffer, ctx->certificate->length); #endif ctx->ownOurCert = 1; } return ctx->ourCert; } return NULL; } #endif /* OPENSSL_EXTRA && KEEP_OUR_CERT */ #endif /* NO_CERTS */ #if !defined(NO_ASN) && (defined(OPENSSL_EXTRA) || \ defined(OPENSSL_EXTRA_X509_SMALL)) void wolfSSL_ASN1_OBJECT_free(WOLFSSL_ASN1_OBJECT* obj) { if (obj == NULL) { return; } if ((obj->obj != NULL) && ((obj->dynamic & WOLFSSL_ASN1_DYNAMIC_DATA) != 0)) { #ifdef WOLFSSL_DEBUG_OPENSSL WOLFSSL_MSG("Freeing ASN1 data"); #endif XFREE((void*)obj->obj, obj->heap, DYNAMIC_TYPE_ASN1); obj->obj = NULL; } #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) if (obj->pathlen != NULL) { wolfSSL_ASN1_INTEGER_free(obj->pathlen); obj->pathlen = NULL; } #endif if ((obj->dynamic & WOLFSSL_ASN1_DYNAMIC) != 0) { #ifdef WOLFSSL_DEBUG_OPENSSL WOLFSSL_MSG("Freeing ASN1 OBJECT"); #endif XFREE(obj, NULL, DYNAMIC_TYPE_ASN1); } } WOLFSSL_ASN1_OBJECT* wolfSSL_ASN1_OBJECT_new(void) { WOLFSSL_ASN1_OBJECT* obj; obj = (WOLFSSL_ASN1_OBJECT*)XMALLOC(sizeof(WOLFSSL_ASN1_OBJECT), NULL, DYNAMIC_TYPE_ASN1); if (obj == NULL) { return NULL; } XMEMSET(obj, 0, sizeof(WOLFSSL_ASN1_OBJECT)); obj->d.ia5 = &(obj->d.ia5_internal); #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) obj->d.iPAddress = &(obj->d.iPAddress_internal); #endif obj->dynamic |= WOLFSSL_ASN1_DYNAMIC; return obj; } WOLFSSL_ASN1_OBJECT* wolfSSL_ASN1_OBJECT_dup(WOLFSSL_ASN1_OBJECT* obj) { WOLFSSL_ASN1_OBJECT* dupl = NULL; WOLFSSL_ENTER("wolfSSL_ASN1_OBJECT_dup"); if (!obj) { WOLFSSL_MSG("Bad parameter"); return NULL; } dupl = wolfSSL_ASN1_OBJECT_new(); if (!dupl) { WOLFSSL_MSG("wolfSSL_ASN1_OBJECT_new error"); return NULL; } /* Copy data */ XMEMCPY(dupl->sName, obj->sName, WOLFSSL_MAX_SNAME); dupl->type = obj->type; dupl->grp = obj->grp; dupl->nid = obj->nid; dupl->objSz = obj->objSz; if (obj->obj) { dupl->obj = (const unsigned char*)XMALLOC( obj->objSz, NULL, DYNAMIC_TYPE_ASN1); if (!dupl->obj) { WOLFSSL_MSG("ASN1 obj malloc error"); wolfSSL_ASN1_OBJECT_free(dupl); return NULL; } XMEMCPY((byte*)dupl->obj, obj->obj, obj->objSz); dupl->dynamic |= WOLFSSL_ASN1_DYNAMIC_DATA; } return dupl; } #endif /* !NO_ASN && (OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL) */ #ifndef NO_ASN #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) /* Creates and returns a new WOLFSSL_CIPHER stack. */ WOLFSSL_STACK* wolfSSL_sk_new_asn1_obj(void) { WOLFSSL_STACK* sk; WOLFSSL_ENTER("wolfSSL_sk_new_asn1_obj"); sk = wolfSSL_sk_new_null(); if (sk == NULL) return NULL; sk->type = STACK_TYPE_OBJ; return sk; } /* return 1 on success 0 on fail */ int wolfSSL_sk_ASN1_OBJECT_push(WOLF_STACK_OF(WOLFSSL_ASN1_OBJECT)* sk, WOLFSSL_ASN1_OBJECT* obj) { WOLFSSL_ENTER("wolfSSL_sk_ASN1_OBJECT_push"); if (sk == NULL || obj == NULL) { return WOLFSSL_FAILURE; } return wolfSSL_sk_push(sk, obj); } WOLFSSL_ASN1_OBJECT* wolfSSL_sk_ASN1_OBJECT_pop( WOLF_STACK_OF(WOLFSSL_ASN1_OBJECT)* sk) { WOLFSSL_STACK* node; WOLFSSL_ASN1_OBJECT* obj; if (sk == NULL) { return NULL; } node = sk->next; obj = sk->data.obj; if (node != NULL) { /* update sk and remove node from stack */ sk->data.obj = node->data.obj; sk->next = node->next; XFREE(node, NULL, DYNAMIC_TYPE_ASN1); } else { /* last obj in stack */ sk->data.obj = NULL; } if (sk->num > 0) { sk->num -= 1; } return obj; } /* Free the structure for ASN1_OBJECT stack * * sk stack to free nodes in */ void wolfSSL_sk_ASN1_OBJECT_free(WOLF_STACK_OF(WOLFSSL_ASN1_OBJECT)* sk) { wolfSSL_sk_free(sk); } /* Free's all nodes in ASN1_OBJECT stack. * This is different then wolfSSL_ASN1_OBJECT_free in that it allows for * choosing the function to use when freeing an ASN1_OBJECT stack. * * sk stack to free nodes in * f X509 free function */ void wolfSSL_sk_ASN1_OBJECT_pop_free(WOLF_STACK_OF(WOLFSSL_ASN1_OBJECT)* sk, void (*f) (WOLFSSL_ASN1_OBJECT*)) { WOLFSSL_ENTER("wolfSSL_sk_ASN1_OBJECT_pop_free"); wolfSSL_sk_pop_free(sk, (wolfSSL_sk_freefunc)f); } #endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */ #endif /* !NO_ASN */ #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) #ifndef NO_ASN int wolfSSL_ASN1_STRING_to_UTF8(unsigned char **out, WOLFSSL_ASN1_STRING *in) { /* ASN1_STRING_to_UTF8() converts the string in to UTF8 format, the converted data is allocated in a buffer in *out. The length of out is returned or a negative error code. The buffer *out should be free using OPENSSL_free(). */ unsigned char* buf; unsigned char* inPtr; int inLen; if (!out || !in) { return -1; } inPtr = wolfSSL_ASN1_STRING_data(in); inLen = wolfSSL_ASN1_STRING_length(in); if (!inPtr || inLen < 0) { return -1; } buf = (unsigned char*)XMALLOC(inLen + 1, NULL, DYNAMIC_TYPE_OPENSSL); if (!buf) { return -1; } XMEMCPY(buf, inPtr, inLen + 1); *out = buf; return inLen; } #endif /* !NO_ASN */ #endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ #if defined(OPENSSL_EXTRA) #ifndef NO_ASN int wolfSSL_ASN1_UNIVERSALSTRING_to_string(WOLFSSL_ASN1_STRING *s) { char *idx; char *copy; WOLFSSL_ENTER("wolfSSL_ASN1_UNIVERSALSTRING_to_string"); if (!s) { WOLFSSL_MSG("Bad parameter"); return WOLFSSL_FAILURE; } if (s->type != V_ASN1_UNIVERSALSTRING) { WOLFSSL_MSG("Input is not a universal string"); return WOLFSSL_FAILURE; } if ((s->length % 4) != 0) { WOLFSSL_MSG("Input string must be divisible by 4"); return WOLFSSL_FAILURE; } for (idx = s->data; idx < s->data + s->length; idx += 4) if ((idx[0] != '\0') || (idx[1] != '\0') || (idx[2] != '\0')) break; if (idx != s->data + s->length) { WOLFSSL_MSG("Wrong string format"); return WOLFSSL_FAILURE; } for (copy = idx = s->data; idx < s->data + s->length; idx += 4) *copy++ = idx[3]; *copy = '\0'; s->length /= 4; s->type = V_ASN1_PRINTABLESTRING; return WOLFSSL_SUCCESS; } /* Returns string representation of ASN1_STRING */ char* wolfSSL_i2s_ASN1_STRING(WOLFSSL_v3_ext_method *method, const WOLFSSL_ASN1_STRING *s) { int i; int tmpSz = 100; int valSz = 5; char* tmp; char val[5]; unsigned char* str; WOLFSSL_ENTER("wolfSSL_i2s_ASN1_STRING"); (void)method; if(s == NULL || s->data == NULL) { WOLFSSL_MSG("Bad Function Argument"); return NULL; } str = (unsigned char*)XMALLOC(s->length, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (str == NULL) { WOLFSSL_MSG("Memory Error"); return NULL; } XMEMCPY(str, (unsigned char*)s->data, s->length); tmp = (char*)XMALLOC(tmpSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (tmp == NULL) { WOLFSSL_MSG("Memory Error"); XFREE(str, NULL, DYNAMIC_TYPE_TMP_BUFFER); return NULL; } XMEMSET(tmp, 0, tmpSz); for (i = 0; i < tmpSz && i < (s->length - 1); i++) { XSNPRINTF(val, valSz - 1, "%02X:", str[i]); XSTRNCAT(tmp, val, valSz); } XSNPRINTF(val, valSz - 1, "%02X", str[i]); XSTRNCAT(tmp, val, valSz); XFREE(str, NULL, DYNAMIC_TYPE_TMP_BUFFER); return tmp; } #endif /* NO_ASN */ #endif /* OPENSSL_EXTRA */ #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) void wolfSSL_set_connect_state(WOLFSSL* ssl) { WOLFSSL_ENTER("wolfSSL_set_connect_state"); if (ssl == NULL) { WOLFSSL_MSG("WOLFSSL struct pointer passed in was null"); return; } #ifndef NO_DH /* client creates its own DH parameters on handshake */ if (ssl->buffers.serverDH_P.buffer && ssl->buffers.weOwnDH) { XFREE(ssl->buffers.serverDH_P.buffer, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); } ssl->buffers.serverDH_P.buffer = NULL; if (ssl->buffers.serverDH_G.buffer && ssl->buffers.weOwnDH) { XFREE(ssl->buffers.serverDH_G.buffer, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); } ssl->buffers.serverDH_G.buffer = NULL; #endif if (InitSSL_Side(ssl, WOLFSSL_CLIENT_END) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("Error initializing client side"); } } #endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */ int wolfSSL_get_shutdown(const WOLFSSL* ssl) { int isShutdown = 0; WOLFSSL_ENTER("wolfSSL_get_shutdown"); if (ssl) { #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; } int wolfSSL_session_reused(WOLFSSL* ssl) { int resuming = 0; WOLFSSL_ENTER("wolfSSL_session_reused"); if (ssl) resuming = ssl->options.resuming; WOLFSSL_LEAVE("wolfSSL_session_reused", resuming); return resuming; } /* return a new malloc'd session with default settings on success */ WOLFSSL_SESSION* wolfSSL_NewSession(void* heap) { WOLFSSL_SESSION* ret = NULL; ret = (WOLFSSL_SESSION*)XMALLOC(sizeof(WOLFSSL_SESSION), heap, DYNAMIC_TYPE_SESSION); if (ret != NULL) { XMEMSET(ret, 0, sizeof(WOLFSSL_SESSION)); #ifndef SINGLE_THREADED if (wc_InitMutex(&ret->refMutex) != 0) { WOLFSSL_MSG("Error setting up session reference mutex"); XFREE(ret, ret->heap, DYNAMIC_TYPE_SESSION); return NULL; } #endif ret->refCount = 1; #ifndef NO_SESSION_CACHE ret->cacheRow = INVALID_SESSION_ROW; /* not in cache */ #endif ret->type = WOLFSSL_SESSION_TYPE_HEAP; ret->heap = heap; ret->masterSecret = ret->_masterSecret; #ifdef WOLFSSL_CHECK_MEM_ZERO wc_MemZero_Add("SESSION master secret", ret->masterSecret, SECRET_LEN); wc_MemZero_Add("SESSION id", ret->sessionID, ID_LEN); #endif #ifndef NO_CLIENT_CACHE ret->serverID = ret->_serverID; #endif #ifdef OPENSSL_EXTRA ret->sessionCtx = ret->_sessionCtx; #endif #ifdef HAVE_SESSION_TICKET ret->ticket = ret->_staticTicket; #endif #ifdef HAVE_STUNNEL /* stunnel has this funny mechanism of storing the "is_authenticated" * session info in the session ex data. This is basically their * default so let's just hard code it. */ if (wolfSSL_SESSION_set_ex_data(ret, 0, (void *)(-1)) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("Error setting up ex data for stunnel"); XFREE(ret, NULL, DYNAMIC_TYPE_SESSION); return NULL; } #endif #ifdef HAVE_EX_DATA ret->ownExData = 1; #endif } return ret; } WOLFSSL_SESSION* wolfSSL_SESSION_new_ex(void* heap) { return wolfSSL_NewSession(heap); } WOLFSSL_SESSION* wolfSSL_SESSION_new(void) { return wolfSSL_SESSION_new_ex(NULL); } /* add one to session reference count * return WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE on error */ int wolfSSL_SESSION_up_ref(WOLFSSL_SESSION* session) { session = ClientSessionToSession(session); if (session == NULL || session->type != WOLFSSL_SESSION_TYPE_HEAP) return WOLFSSL_FAILURE; #ifndef SINGLE_THREADED if (wc_LockMutex(&session->refMutex) != 0) { WOLFSSL_MSG("Failed to lock session mutex"); return WOLFSSL_FAILURE; } #endif session->refCount++; #ifndef SINGLE_THREADED wc_UnLockMutex(&session->refMutex); #endif return WOLFSSL_SUCCESS; } /** * Deep copy the contents from input to output. * @param input The source of the copy. * @param output The destination of the copy. * @param avoidSysCalls If true, then system calls will be avoided or an error * will be returned if it is not possible to proceed * without a system call. This is useful for fetching * sessions from cache. When a cache row is locked, we * don't want to block other threads with long running * system calls. * @return WOLFSSL_SUCCESS on success * WOLFSSL_FAILURE on failure */ int wolfSSL_DupSession(const WOLFSSL_SESSION* input, WOLFSSL_SESSION* output, int avoidSysCalls) { #ifdef HAVE_SESSION_TICKET int ticLenAlloc = 0; byte *ticBuff = NULL; #endif const size_t copyOffset = OFFSETOF(WOLFSSL_SESSION, heap) + sizeof(input->heap); int ret = WOLFSSL_SUCCESS; (void)avoidSysCalls; input = ClientSessionToSession(input); output = ClientSessionToSession(output); if (input == NULL || output == NULL || input == output) { WOLFSSL_MSG("input or output are null or same"); return WOLFSSL_FAILURE; } #ifdef HAVE_SESSION_TICKET if (output->ticket != output->_staticTicket) { ticBuff = output->ticket; ticLenAlloc = output->ticketLenAlloc; } #endif #if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) if (output->peer != NULL) { if (avoidSysCalls) { WOLFSSL_MSG("Can't free cert when avoiding syscalls"); return WOLFSSL_FAILURE; } wolfSSL_X509_free(output->peer); output->peer = NULL; } #endif XMEMCPY((byte*)output + copyOffset, (byte*)input + copyOffset, sizeof(WOLFSSL_SESSION) - copyOffset); /* Set sane values for copy */ if (output->type != WOLFSSL_SESSION_TYPE_CACHE) #ifndef NO_SESSION_CACHE output->cacheRow = INVALID_SESSION_ROW; #endif #if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) if (input->peer != NULL && input->peer->dynamicMemory) { if (wolfSSL_X509_up_ref(input->peer) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("Can't increase peer cert ref count"); output->peer = NULL; } } else if (!avoidSysCalls) output->peer = wolfSSL_X509_dup(input->peer); else /* output->peer is not that important to copy */ output->peer = NULL; #endif output->masterSecret = output->_masterSecret; #ifndef NO_CLIENT_CACHE output->serverID = output->_serverID; #endif #ifdef OPENSSL_EXTRA output->sessionCtx = output->_sessionCtx; #endif #ifdef HAVE_SESSION_TICKET if (input->ticketLen > SESSION_TICKET_LEN) { /* Need dynamic buffer */ if (ticBuff == NULL || ticLenAlloc < input->ticketLen) { /* allocate new one */ byte* tmp; if (!avoidSysCalls) { WOLFSSL_MSG("Failed to allocate memory for ticket when avoiding" " syscalls"); output->ticket = ticBuff; output->ticketLenAlloc = (word16) ticLenAlloc; output->ticketLen = 0; ret = WOLFSSL_FAILURE; } else { tmp = (byte*)XREALLOC(ticBuff, input->ticketLen, output->heap, DYNAMIC_TYPE_SESSION_TICK); if (tmp == NULL) { WOLFSSL_MSG("Failed to allocate memory for ticket"); XFREE(ticBuff, output->heap, DYNAMIC_TYPE_SESSION_TICK); output->ticket = NULL; output->ticketLen = 0; output->ticketLenAlloc = 0; ret = WOLFSSL_FAILURE; } else { ticBuff = tmp; ticLenAlloc = input->ticketLen; } } } if (ticBuff != NULL && ret == WOLFSSL_SUCCESS) { XMEMCPY(ticBuff, input->ticket, input->ticketLen); output->ticket = ticBuff; output->ticketLenAlloc = (word16) ticLenAlloc; } } else { /* Default ticket to non dynamic */ if (avoidSysCalls) { /* Try to use ticBuf if available. Caller can later move it to * the static buffer. */ if (ticBuff != NULL) { if (ticLenAlloc >= input->ticketLen) { output->ticket = output->_staticTicket; output->ticketLenAlloc = 0; } else { WOLFSSL_MSG("ticket dynamic buffer too small but we are " "avoiding system calls"); ret = WOLFSSL_FAILURE; output->ticket = ticBuff; output->ticketLenAlloc = (word16) ticLenAlloc; output->ticketLen = 0; } } else { output->ticket = output->_staticTicket; output->ticketLenAlloc = 0; } } else { if (ticBuff != NULL) XFREE(ticBuff, output->heap, DYNAMIC_TYPE_SESSION_TICK); output->ticket = output->_staticTicket; output->ticketLenAlloc = 0; } if (input->ticketLenAlloc > 0 && ret == WOLFSSL_SUCCESS) { /* Shouldn't happen as session should have placed this in * the static buffer */ XMEMCPY(output->ticket, input->ticket, input->ticketLen); } } ticBuff = NULL; #endif /* HAVE_SESSION_TICKET */ return ret; } WOLFSSL_SESSION* wolfSSL_SESSION_dup(WOLFSSL_SESSION* session) { #ifdef HAVE_EXT_CACHE WOLFSSL_SESSION* copy; WOLFSSL_ENTER("wolfSSL_SESSION_dup"); session = ClientSessionToSession(session); if (session == NULL) return NULL; #ifdef HAVE_SESSION_TICKET if (session->ticketLenAlloc > 0 && !session->ticket) { WOLFSSL_MSG("Session dynamic flag is set but ticket pointer is null"); return NULL; } #endif copy = wolfSSL_NewSession(session->heap); if (copy != NULL && wolfSSL_DupSession(session, copy, 0) != WOLFSSL_SUCCESS) { wolfSSL_FreeSession(NULL, copy); copy = NULL; } return copy; #else WOLFSSL_MSG("wolfSSL_SESSION_dup feature not compiled in"); (void)session; return NULL; #endif /* HAVE_EXT_CACHE */ } void wolfSSL_FreeSession(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* session) { session = ClientSessionToSession(session); if (session == NULL) return; (void)ctx; /* refCount will always be 1 or more if created externally. * Internal cache sessions don't initialize a refMutex. */ if (session->refCount > 0) { #ifndef SINGLE_THREADED if (wc_LockMutex(&session->refMutex) != 0) { WOLFSSL_MSG("Failed to lock session mutex"); return; } #endif if (session->refCount > 1) { session->refCount--; #ifndef SINGLE_THREADED wc_UnLockMutex(&session->refMutex); #endif return; } #ifndef SINGLE_THREADED wc_UnLockMutex(&session->refMutex); wc_FreeMutex(&session->refMutex); #endif } #if defined(HAVE_EXT_CACHE) || defined(HAVE_EX_DATA) if (ctx != NULL && ctx->rem_sess_cb #ifdef HAVE_EX_DATA && session->ownExData /* This will be true if we are not using the * internal cache so it will get called for * externally cached sessions as well. */ #endif ) { ctx->rem_sess_cb(ctx, session); } #endif #ifdef HAVE_EX_DATA_CLEANUP_HOOKS wolfSSL_CRYPTO_cleanup_ex_data(&session->ex_data); #endif #if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) if (session->peer) { wolfSSL_X509_free(session->peer); session->peer = NULL; } #endif #ifdef HAVE_SESSION_TICKET if (session->ticketLenAlloc > 0) { XFREE(session->ticket, session->heap, DYNAMIC_TYPE_SESSION_TICK); } #endif #ifdef HAVE_EX_DATA_CLEANUP_HOOKS wolfSSL_CRYPTO_cleanup_ex_data(&session->ex_data); #endif /* Make sure masterSecret is zeroed. */ ForceZero(session->masterSecret, SECRET_LEN); /* Session ID is sensitive information too. */ ForceZero(session->sessionID, ID_LEN); if (session->type == WOLFSSL_SESSION_TYPE_HEAP) { XFREE(session, session->heap, DYNAMIC_TYPE_SESSION); } } void wolfSSL_SESSION_free(WOLFSSL_SESSION* session) { session = ClientSessionToSession(session); wolfSSL_FreeSession(NULL, session); } #ifndef NO_SESSION_CACHE int wolfSSL_CTX_add_session(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* session) { int error = 0; const byte* id = NULL; byte idSz = 0; WOLFSSL_ENTER("wolfSSL_CTX_add_session"); session = ClientSessionToSession(session); if (session == NULL) return WOLFSSL_FAILURE; /* Session cache is global */ (void)ctx; id = session->sessionID; idSz = session->sessionIDSz; if (session->haveAltSessionID) { id = session->altSessionID; idSz = ID_LEN; } error = AddSessionToCache(ctx, session, id, idSz, NULL, session->side, #ifdef HAVE_SESSION_TICKET session->ticketLen > 0, #else 0, #endif NULL); return error == 0 ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; } #endif #if defined(OPENSSL_EXTRA) || defined(HAVE_EXT_CACHE) /** * set cipher to WOLFSSL_SESSION from WOLFSSL_CIPHER * @param session a pointer to WOLFSSL_SESSION structure * @param cipher a function pointer to WOLFSSL_CIPHER * @return WOLFSSL_SUCCESS on success, otherwise WOLFSSL_FAILURE */ int wolfSSL_SESSION_set_cipher(WOLFSSL_SESSION* session, const WOLFSSL_CIPHER* cipher) { WOLFSSL_ENTER("wolfSSL_SESSION_set_cipher"); session = ClientSessionToSession(session); /* sanity check */ if (session == NULL || cipher == NULL) { WOLFSSL_MSG("bad argument"); return WOLFSSL_FAILURE; } session->cipherSuite0 = cipher->cipherSuite0; session->cipherSuite = cipher->cipherSuite; WOLFSSL_LEAVE("wolfSSL_SESSION_set_cipher", WOLFSSL_SUCCESS); return WOLFSSL_SUCCESS; } #endif /* OPENSSL_EXTRA || HAVE_EXT_CACHE */ /* helper function that takes in a protocol version struct and returns string */ static const char* wolfSSL_internal_get_version(const ProtocolVersion* version) { WOLFSSL_ENTER("wolfSSL_get_version"); if (version == NULL) { return "Bad arg"; } if (version->major == SSLv3_MAJOR) { switch (version->minor) { case SSLv3_MINOR : return "SSLv3"; case TLSv1_MINOR : return "TLSv1"; case TLSv1_1_MINOR : return "TLSv1.1"; case TLSv1_2_MINOR : return "TLSv1.2"; case TLSv1_3_MINOR : return "TLSv1.3"; default: return "unknown"; } } #ifdef WOLFSSL_DTLS else if (version->major == DTLS_MAJOR) { switch (version->minor) { case DTLS_MINOR : return "DTLS"; case DTLSv1_2_MINOR : return "DTLSv1.2"; case DTLSv1_3_MINOR : return "DTLSv1.3"; default: return "unknown"; } } #endif /* WOLFSSL_DTLS */ return "unknown"; } const char* wolfSSL_get_version(const WOLFSSL* ssl) { if (ssl == NULL) { WOLFSSL_MSG("Bad argument"); return "unknown"; } return wolfSSL_internal_get_version(&ssl->version); } /* current library version */ const char* wolfSSL_lib_version(void) { return LIBWOLFSSL_VERSION_STRING; } #ifdef OPENSSL_EXTRA #if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000L const char* wolfSSL_OpenSSL_version(int a) { (void)a; return "wolfSSL " LIBWOLFSSL_VERSION_STRING; } #else const char* wolfSSL_OpenSSL_version(void) { return "wolfSSL " LIBWOLFSSL_VERSION_STRING; } #endif /* WOLFSSL_QT */ #endif /* current library version in hex */ word32 wolfSSL_lib_version_hex(void) { return LIBWOLFSSL_VERSION_HEX; } int wolfSSL_get_current_cipher_suite(WOLFSSL* ssl) { WOLFSSL_ENTER("SSL_get_current_cipher_suite"); if (ssl) return (ssl->options.cipherSuite0 << 8) | ssl->options.cipherSuite; return 0; } WOLFSSL_CIPHER* wolfSSL_get_current_cipher(WOLFSSL* ssl) { WOLFSSL_ENTER("SSL_get_current_cipher"); 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 return NULL; } const char* wolfSSL_CIPHER_get_name(const WOLFSSL_CIPHER* cipher) { WOLFSSL_ENTER("wolfSSL_CIPHER_get_name"); if (cipher == NULL) { return NULL; } #if !defined(WOLFSSL_CIPHER_INTERNALNAME) && !defined(NO_ERROR_STRINGS) && \ !defined(WOLFSSL_QT) return GetCipherNameIana(cipher->cipherSuite0, cipher->cipherSuite); #else return wolfSSL_get_cipher_name_from_suite(cipher->cipherSuite0, cipher->cipherSuite); #endif } const char* wolfSSL_CIPHER_get_version(const WOLFSSL_CIPHER* cipher) { WOLFSSL_ENTER("SSL_CIPHER_get_version"); if (cipher == NULL || cipher->ssl == NULL) { return NULL; } return wolfSSL_get_version(cipher->ssl); } const char* wolfSSL_SESSION_CIPHER_get_name(const WOLFSSL_SESSION* session) { session = ClientSessionToSession(session); if (session == NULL) { return NULL; } #if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \ (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) #if !defined(WOLFSSL_CIPHER_INTERNALNAME) && !defined(NO_ERROR_STRINGS) return GetCipherNameIana(session->cipherSuite0, session->cipherSuite); #else return GetCipherNameInternal(session->cipherSuite0, session->cipherSuite); #endif #else return NULL; #endif } const char* wolfSSL_get_cipher(WOLFSSL* ssl) { WOLFSSL_ENTER("wolfSSL_get_cipher"); return wolfSSL_CIPHER_get_name(wolfSSL_get_current_cipher(ssl)); } /* gets cipher name in the format DHE-RSA-... rather then TLS_DHE... */ const char* wolfSSL_get_cipher_name(WOLFSSL* ssl) { /* get access to cipher_name_idx in internal.c */ return wolfSSL_get_cipher_name_internal(ssl); } const char* wolfSSL_get_cipher_name_from_suite(const byte cipherSuite0, const byte cipherSuite) { return GetCipherNameInternal(cipherSuite0, cipherSuite); } const char* wolfSSL_get_cipher_name_iana_from_suite(const byte cipherSuite0, const byte cipherSuite) { return GetCipherNameIana(cipherSuite0, cipherSuite); } int wolfSSL_get_cipher_suite_from_name(const char* name, byte* cipherSuite0, byte* cipherSuite, int *flags) { if ((name == NULL) || (cipherSuite0 == NULL) || (cipherSuite == NULL) || (flags == NULL)) return BAD_FUNC_ARG; return GetCipherSuiteFromName(name, cipherSuite0, cipherSuite, flags); } #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) /* Creates and returns a new WOLFSSL_CIPHER stack. */ WOLFSSL_STACK* wolfSSL_sk_new_cipher(void) { WOLFSSL_STACK* sk; WOLFSSL_ENTER("wolfSSL_sk_new_cipher"); sk = wolfSSL_sk_new_null(); if (sk == NULL) return NULL; sk->type = STACK_TYPE_CIPHER; return sk; } /* return 1 on success 0 on fail */ int wolfSSL_sk_CIPHER_push(WOLF_STACK_OF(WOLFSSL_CIPHER)* sk, WOLFSSL_CIPHER* cipher) { return wolfSSL_sk_push(sk, cipher); } #ifndef NO_WOLFSSL_STUB WOLFSSL_CIPHER* wolfSSL_sk_CIPHER_pop(WOLF_STACK_OF(WOLFSSL_CIPHER)* sk) { WOLFSSL_STUB("wolfSSL_sk_CIPHER_pop"); (void)sk; return NULL; } #endif /* NO_WOLFSSL_STUB */ #endif /* WOLFSSL_QT || OPENSSL_ALL */ word32 wolfSSL_CIPHER_get_id(const WOLFSSL_CIPHER* cipher) { word16 cipher_id = 0; WOLFSSL_ENTER("SSL_CIPHER_get_id"); if (cipher && cipher->ssl) { cipher_id = (cipher->ssl->options.cipherSuite0 << 8) | cipher->ssl->options.cipherSuite; } return cipher_id; } const WOLFSSL_CIPHER* wolfSSL_get_cipher_by_value(word16 value) { const WOLFSSL_CIPHER* cipher = NULL; byte cipherSuite0, cipherSuite; WOLFSSL_ENTER("SSL_get_cipher_by_value"); /* extract cipher id information */ cipherSuite = (value & 0xFF); cipherSuite0 = ((value >> 8) & 0xFF); /* TODO: lookup by cipherSuite0 / cipherSuite */ (void)cipherSuite0; (void)cipherSuite; return cipher; } #if defined(OPENSSL_EXTRA) /* Free the structure for WOLFSSL_CIPHER stack * * sk stack to free nodes in */ void wolfSSL_sk_CIPHER_free(WOLF_STACK_OF(WOLFSSL_CIPHER)* sk) { WOLFSSL_ENTER("wolfSSL_sk_CIPHER_free"); wolfSSL_sk_free(sk); } #endif /* OPENSSL_ALL */ #if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || defined(HAVE_CURVE448) || \ !defined(NO_DH) #ifdef HAVE_FFDHE static const char* wolfssl_ffdhe_name(word16 group) { const char* str = NULL; switch (group) { case WOLFSSL_FFDHE_2048: str = "FFDHE_2048"; break; case WOLFSSL_FFDHE_3072: str = "FFDHE_3072"; break; case WOLFSSL_FFDHE_4096: str = "FFDHE_4096"; break; case WOLFSSL_FFDHE_6144: str = "FFDHE_6144"; break; case WOLFSSL_FFDHE_8192: str = "FFDHE_8192"; break; default: break; } return str; } #endif /* Return the name of the curve used for key exchange as a printable string. * * ssl The SSL/TLS object. * returns NULL if ECDH was not used, otherwise the name as a string. */ const char* wolfSSL_get_curve_name(WOLFSSL* ssl) { const char* cName = NULL; if (ssl == NULL) return NULL; #ifdef HAVE_FFDHE if (ssl->namedGroup != 0) { cName = wolfssl_ffdhe_name(ssl->namedGroup); } #endif #ifdef HAVE_CURVE25519 if (ssl->ecdhCurveOID == ECC_X25519_OID && cName == NULL) { cName = "X25519"; } #endif #ifdef HAVE_CURVE448 if (ssl->ecdhCurveOID == ECC_X448_OID && cName == NULL) { cName = "X448"; } #endif #ifdef HAVE_ECC if (ssl->ecdhCurveOID != 0 && cName == NULL) { cName = wc_ecc_get_name(wc_ecc_get_oid(ssl->ecdhCurveOID, NULL, NULL)); } #endif return cName; } #endif #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) || \ defined(OPENSSL_EXTRA_X509_SMALL) /* Creates a new WOLFSSL_ASN1_STRING structure. * * returns a pointer to the new structure created on success or NULL if fail */ WOLFSSL_ASN1_STRING* wolfSSL_ASN1_STRING_new(void) { WOLFSSL_ASN1_STRING* asn1; #ifdef WOLFSSL_DEBUG_OPENSSL WOLFSSL_ENTER("wolfSSL_ASN1_STRING_new"); #endif asn1 = (WOLFSSL_ASN1_STRING*)XMALLOC(sizeof(WOLFSSL_ASN1_STRING), NULL, DYNAMIC_TYPE_OPENSSL); if (asn1 != NULL) { XMEMSET(asn1, 0, sizeof(WOLFSSL_ASN1_STRING)); } return asn1; /* no check for null because error case is returning null*/ } /** * Used to duplicate a passed in WOLFSSL_ASN1_STRING* * @param asn1 WOLFSSL_ASN1_STRING* to be duplicated * @return WOLFSSL_ASN1_STRING* the duplicate struct or NULL on error */ WOLFSSL_ASN1_STRING* wolfSSL_ASN1_STRING_dup(WOLFSSL_ASN1_STRING* asn1) { WOLFSSL_ASN1_STRING* dupl = NULL; WOLFSSL_ENTER("wolfSSL_ASN1_STRING_dup"); if (!asn1) { WOLFSSL_MSG("Bad parameter"); return NULL; } dupl = wolfSSL_ASN1_STRING_new(); if (!dupl) { WOLFSSL_MSG("wolfSSL_ASN1_STRING_new error"); return NULL; } dupl->type = asn1->type; dupl->flags = asn1->flags; if (wolfSSL_ASN1_STRING_set(dupl, asn1->data, asn1->length) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("wolfSSL_ASN1_STRING_set error"); wolfSSL_ASN1_STRING_free(dupl); return NULL; } return dupl; } /* used to free a WOLFSSL_ASN1_STRING structure */ void wolfSSL_ASN1_STRING_free(WOLFSSL_ASN1_STRING* asn1) { #ifdef WOLFSSL_DEBUG_OPENSSL WOLFSSL_ENTER("wolfSSL_ASN1_STRING_free"); #endif if (asn1 != NULL) { if (asn1->length > 0 && asn1->data != NULL && asn1->isDynamic) { XFREE(asn1->data, NULL, DYNAMIC_TYPE_OPENSSL); } XFREE(asn1, NULL, DYNAMIC_TYPE_OPENSSL); } } int wolfSSL_ASN1_STRING_cmp(const WOLFSSL_ASN1_STRING *a, const WOLFSSL_ASN1_STRING *b) { int i; WOLFSSL_ENTER("wolfSSL_ASN1_STRING_cmp"); if (!a || !b) { return WOLFSSL_FATAL_ERROR; } if (a->length != b->length) { return a->length - b->length; } if ((i = XMEMCMP(a->data, b->data, a->length)) != 0) { return i; } return a->type - b->type; } #endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */ #if !defined(NO_CERTS) && (defined(OPENSSL_EXTRA) || \ defined(OPENSSL_EXTRA_X509_SMALL)) int wolfSSL_ASN1_STRING_copy(WOLFSSL_ASN1_STRING* dest, const WOLFSSL_ASN1_STRING* src) { if (src == NULL || dest == NULL) { return WOLFSSL_FAILURE; } dest->type = src->type; if(wolfSSL_ASN1_STRING_set(dest, src->data, src->length) != WOLFSSL_SUCCESS) { return WOLFSSL_FAILURE; } dest->flags = src->flags; return WOLFSSL_SUCCESS; } /* Creates a new WOLFSSL_ASN1_STRING structure given the input type. * * type is the type of set when WOLFSSL_ASN1_STRING is created * * returns a pointer to the new structure created on success or NULL if fail */ WOLFSSL_ASN1_STRING* wolfSSL_ASN1_STRING_type_new(int type) { WOLFSSL_ASN1_STRING* asn1; #ifdef WOLFSSL_DEBUG_OPENSSL WOLFSSL_ENTER("wolfSSL_ASN1_STRING_type_new"); #endif asn1 = wolfSSL_ASN1_STRING_new(); if (asn1 == NULL) { return NULL; } asn1->type = type; return asn1; } /****************************************************************************** * wolfSSL_ASN1_STRING_type - returns the type of * * RETURNS: * returns the type set for . Otherwise, returns WOLFSSL_FAILURE. */ int wolfSSL_ASN1_STRING_type(const WOLFSSL_ASN1_STRING* asn1) { #ifdef WOLFSSL_DEBUG_OPENSSL WOLFSSL_ENTER("wolfSSL_ASN1_STRING_type"); #endif if (asn1 == NULL) { return WOLFSSL_FAILURE; } return asn1->type; } #endif /* !NO_CERTS && OPENSSL_EXTRA */ #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) || \ defined(OPENSSL_EXTRA_X509_SMALL) /* if dataSz is negative then use XSTRLEN to find length of data * return WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE on failure */ /* `data` can be NULL and only buffer will be allocated */ int wolfSSL_ASN1_STRING_set(WOLFSSL_ASN1_STRING* asn1, const void* data, int dataSz) { int sz; #ifdef WOLFSSL_DEBUG_OPENSSL WOLFSSL_ENTER("wolfSSL_ASN1_STRING_set"); #endif if (asn1 == NULL || (data == NULL && dataSz < 0)) { return WOLFSSL_FAILURE; } if (dataSz < 0) { sz = (int)XSTRLEN((const char*)data); } else { sz = dataSz; } if (sz < 0) { return WOLFSSL_FAILURE; } /* free any existing data before copying */ if (asn1->data != NULL && asn1->isDynamic) { XFREE(asn1->data, NULL, DYNAMIC_TYPE_OPENSSL); asn1->data = NULL; } if (sz + 1 > CTC_NAME_SIZE) { /* account for null char */ /* create new data buffer and copy over */ asn1->data = (char*)XMALLOC(sz + 1, NULL, DYNAMIC_TYPE_OPENSSL); if (asn1->data == NULL) { return WOLFSSL_FAILURE; } asn1->isDynamic = 1; } else { XMEMSET(asn1->strData, 0, CTC_NAME_SIZE); asn1->data = asn1->strData; asn1->isDynamic = 0; } if (data != NULL) { XMEMCPY(asn1->data, data, sz); asn1->data[sz] = '\0'; } asn1->length = sz; return WOLFSSL_SUCCESS; } #endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */ #ifndef NO_CERTS #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) const unsigned char* wolfSSL_ASN1_STRING_get0_data( const WOLFSSL_ASN1_STRING* asn) { WOLFSSL_ENTER("wolfSSL_ASN1_STRING_get0_data"); if (asn) { return (const unsigned char*)asn->data; } else { return NULL; } } unsigned char* wolfSSL_ASN1_STRING_data(WOLFSSL_ASN1_STRING* asn) { #ifdef WOLFSSL_DEBUG_OPENSSL WOLFSSL_ENTER("wolfSSL_ASN1_STRING_data"); #endif if (asn) { return (unsigned char*)asn->data; } else { return NULL; } } int wolfSSL_ASN1_STRING_length(WOLFSSL_ASN1_STRING* asn) { #ifdef WOLFSSL_DEBUG_OPENSSL WOLFSSL_ENTER("wolfSSL_ASN1_STRING_length"); #endif if (asn) { return asn->length; } else { return 0; } } #endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ #ifdef OPENSSL_EXTRA #ifndef NO_WOLFSSL_STUB WOLFSSL_ASN1_STRING* wolfSSL_d2i_DISPLAYTEXT(WOLFSSL_ASN1_STRING **asn, const unsigned char **in, long len) { WOLFSSL_STUB("d2i_DISPLAYTEXT"); (void)asn; (void)in; (void)len; return NULL; } #endif #endif /* OPENSSL_EXTRA */ #endif /* !NO_CERTS */ #ifdef OPENSSL_EXTRA #if defined(OPENSSL_ALL) || defined(WOLFSSL_QT) /* return authentication NID corresponding to cipher suite * @param cipher a pointer to WOLFSSL_CIPHER * return NID if found, NID_undef if not found */ int wolfSSL_CIPHER_get_auth_nid(const WOLFSSL_CIPHER* cipher) { static const struct authnid { const char* alg_name; const int nid; } authnid_tbl[] = { {"RSA", NID_auth_rsa}, {"PSK", NID_auth_psk}, {"SRP", NID_auth_srp}, {"ECDSA", NID_auth_ecdsa}, {"None", NID_auth_null}, {NULL, NID_undef} }; const struct authnid* sa; const char* authStr; char n[MAX_SEGMENTS][MAX_SEGMENT_SZ] = {{0}}; if (GetCipherSegment(cipher, n) == NULL) { WOLFSSL_MSG("no suitable cipher name found"); return NID_undef; } authStr = GetCipherAuthStr(n); if (authStr != NULL) { for(sa = authnid_tbl; sa->alg_name != NULL; sa++) { if (XSTRCMP(sa->alg_name, authStr) == 0) { return sa->nid; } } } return NID_undef; } /* return cipher NID corresponding to cipher suite * @param cipher a pointer to WOLFSSL_CIPHER * return NID if found, NID_undef if not found */ int wolfSSL_CIPHER_get_cipher_nid(const WOLFSSL_CIPHER* cipher) { static const struct ciphernid { const char* alg_name; const int nid; } ciphernid_tbl[] = { {"AESGCM(256)", NID_aes_256_gcm}, {"AESGCM(128)", NID_aes_128_gcm}, {"AESCCM(128)", NID_aes_128_ccm}, {"AES(128)", NID_aes_128_cbc}, {"AES(256)", NID_aes_256_cbc}, {"CAMELLIA(256)", NID_camellia_256_cbc}, {"CAMELLIA(128)", NID_camellia_128_cbc}, {"RC4", NID_rc4}, {"3DES", NID_des_ede3_cbc}, {"CHACHA20/POLY1305(256)", NID_chacha20_poly1305}, {"None", NID_undef}, {NULL, NID_undef} }; const struct ciphernid* c; const char* encStr; char n[MAX_SEGMENTS][MAX_SEGMENT_SZ] = {{0}}; WOLFSSL_ENTER("wolfSSL_CIPHER_get_cipher_nid"); if (GetCipherSegment(cipher, n) == NULL) { WOLFSSL_MSG("no suitable cipher name found"); return NID_undef; } encStr = GetCipherEncStr(n); if (encStr != NULL) { for(c = ciphernid_tbl; c->alg_name != NULL; c++) { if (XSTRCMP(c->alg_name, encStr) == 0) { return c->nid; } } } return NID_undef; } /* return digest NID corresponding to cipher suite * @param cipher a pointer to WOLFSSL_CIPHER * return NID if found, NID_undef if not found */ int wolfSSL_CIPHER_get_digest_nid(const WOLFSSL_CIPHER* cipher) { static const struct macnid { const char* alg_name; const int nid; } macnid_tbl[] = { {"SHA1", NID_sha1}, {"SHA256", NID_sha256}, {"SHA384", NID_sha384}, {NULL, NID_undef} }; const struct macnid* mc; const char* name; const char* macStr; char n[MAX_SEGMENTS][MAX_SEGMENT_SZ] = {{0}}; (void)name; WOLFSSL_ENTER("wolfSSL_CIPHER_get_digest_nid"); if ((name = GetCipherSegment(cipher, n)) == NULL) { WOLFSSL_MSG("no suitable cipher name found"); return NID_undef; } /* in MD5 case, NID will be NID_md5 */ if (XSTRSTR(name, "MD5") != NULL) { return NID_md5; } macStr = GetCipherMacStr(n); if (macStr != NULL) { for(mc = macnid_tbl; mc->alg_name != NULL; mc++) { if (XSTRCMP(mc->alg_name, macStr) == 0) { return mc->nid; } } } return NID_undef; } /* return key exchange NID corresponding to cipher suite * @param cipher a pointer to WOLFSSL_CIPHER * return NID if found, NID_undef if not found */ int wolfSSL_CIPHER_get_kx_nid(const WOLFSSL_CIPHER* cipher) { static const struct kxnid { const char* name; const int nid; } kxnid_table[] = { {"ECDHEPSK", NID_kx_ecdhe_psk}, {"ECDH", NID_kx_ecdhe}, {"DHEPSK", NID_kx_dhe_psk}, {"DH", NID_kx_dhe}, {"RSAPSK", NID_kx_rsa_psk}, {"SRP", NID_kx_srp}, {"EDH", NID_kx_dhe}, {"RSA", NID_kx_rsa}, {NULL, NID_undef} }; const struct kxnid* k; const char* keaStr; char n[MAX_SEGMENTS][MAX_SEGMENT_SZ] = {{0}}; WOLFSSL_ENTER("wolfSSL_CIPHER_get_kx_nid"); if (GetCipherSegment(cipher, n) == NULL) { WOLFSSL_MSG("no suitable cipher name found"); return NID_undef; } /* in TLS 1.3 case, NID will be NID_kx_any */ if (XSTRCMP(n[0], "TLS13") == 0) { return NID_kx_any; } keaStr = GetCipherKeaStr(n); if (keaStr != NULL) { for(k = kxnid_table; k->name != NULL; k++) { if (XSTRCMP(k->name, keaStr) == 0) { return k->nid; } } } return NID_undef; } /* check if cipher suite is AEAD * @param cipher a pointer to WOLFSSL_CIPHER * return 1 if cipher is AEAD, 0 otherwise */ int wolfSSL_CIPHER_is_aead(const WOLFSSL_CIPHER* cipher) { char n[MAX_SEGMENTS][MAX_SEGMENT_SZ] = {{0}}; WOLFSSL_ENTER("wolfSSL_CIPHER_is_aead"); if (GetCipherSegment(cipher, n) == NULL) { WOLFSSL_MSG("no suitable cipher name found"); return NID_undef; } return IsCipherAEAD(n); } /* Creates cipher->description based on cipher->offset * cipher->offset is set in wolfSSL_get_ciphers_compat when it is added * to a stack of ciphers. * @param [in] cipher: A cipher from a stack of ciphers. * return WOLFSSL_SUCCESS if cipher->description is set, else WOLFSSL_FAILURE */ int wolfSSL_sk_CIPHER_description(WOLFSSL_CIPHER* cipher) { int strLen; unsigned long offset; char* dp; const char* name; const char *keaStr, *authStr, *encStr, *macStr, *protocol; char n[MAX_SEGMENTS][MAX_SEGMENT_SZ] = {{0}}; int len = MAX_DESCRIPTION_SZ-1; const CipherSuiteInfo* cipher_names; ProtocolVersion pv; WOLFSSL_ENTER("wolfSSL_sk_CIPHER_description"); if (cipher == NULL) return WOLFSSL_FAILURE; dp = cipher->description; if (dp == NULL) return WOLFSSL_FAILURE; cipher_names = GetCipherNames(); offset = cipher->offset; if (offset >= (unsigned long)GetCipherNamesSize()) return WOLFSSL_FAILURE; pv.major = cipher_names[offset].major; pv.minor = cipher_names[offset].minor; protocol = wolfSSL_internal_get_version(&pv); if ((name = GetCipherSegment(cipher, n)) == NULL) { WOLFSSL_MSG("no suitable cipher name found"); return WOLFSSL_FAILURE; } /* keaStr */ keaStr = GetCipherKeaStr(n); /* authStr */ authStr = GetCipherAuthStr(n); /* encStr */ encStr = GetCipherEncStr(n); if ((cipher->bits = SetCipherBits(encStr)) == WOLFSSL_FAILURE) { WOLFSSL_MSG("Cipher Bits Not Set."); } /* macStr */ macStr = GetCipherMacStr(n); /* Build up the string by copying onto the end. */ XSTRNCPY(dp, name, len); dp[len-1] = '\0'; strLen = (int)XSTRLEN(dp); len -= strLen; dp += strLen; XSTRNCPY(dp, " ", len); dp[len-1] = '\0'; strLen = (int)XSTRLEN(dp); len -= strLen; dp += strLen; XSTRNCPY(dp, protocol, len); dp[len-1] = '\0'; strLen = (int)XSTRLEN(dp); len -= strLen; dp += strLen; XSTRNCPY(dp, " Kx=", len); dp[len-1] = '\0'; strLen = (int)XSTRLEN(dp); len -= strLen; dp += strLen; XSTRNCPY(dp, keaStr, len); dp[len-1] = '\0'; strLen = (int)XSTRLEN(dp); len -= strLen; dp += strLen; XSTRNCPY(dp, " Au=", len); dp[len-1] = '\0'; strLen = (int)XSTRLEN(dp); len -= strLen; dp += strLen; XSTRNCPY(dp, authStr, len); dp[len-1] = '\0'; strLen = (int)XSTRLEN(dp); len -= strLen; dp += strLen; XSTRNCPY(dp, " Enc=", len); dp[len-1] = '\0'; strLen = (int)XSTRLEN(dp); len -= strLen; dp += strLen; XSTRNCPY(dp, encStr, len); dp[len-1] = '\0'; strLen = (int)XSTRLEN(dp); len -= strLen; dp += strLen; XSTRNCPY(dp, " Mac=", len); dp[len-1] = '\0'; strLen = (int)XSTRLEN(dp); len -= strLen; dp += strLen; XSTRNCPY(dp, macStr, len); dp[len-1] = '\0'; return WOLFSSL_SUCCESS; } #endif /* OPENSSL_ALL || WOLFSSL_QT */ static WC_INLINE const char* wolfssl_kea_to_string(int kea) { const char* keaStr; switch (kea) { case no_kea: keaStr = "None"; break; #ifndef NO_RSA case rsa_kea: keaStr = "RSA"; break; #endif #ifndef NO_DH case diffie_hellman_kea: keaStr = "DHE"; break; #endif case fortezza_kea: keaStr = "FZ"; break; #ifndef NO_PSK case psk_kea: keaStr = "PSK"; break; #ifndef NO_DH case dhe_psk_kea: keaStr = "DHEPSK"; break; #endif #ifdef HAVE_ECC case ecdhe_psk_kea: keaStr = "ECDHEPSK"; break; #endif #endif #ifdef HAVE_ECC case ecc_diffie_hellman_kea: keaStr = "ECDHE"; break; case ecc_static_diffie_hellman_kea: keaStr = "ECDH"; break; #endif default: keaStr = "unknown"; break; } return keaStr; } static WC_INLINE const char* wolfssl_sigalg_to_string(int sig_algo) { const char* authStr; switch (sig_algo) { case anonymous_sa_algo: authStr = "None"; break; #ifndef NO_RSA case rsa_sa_algo: authStr = "RSA"; break; #ifdef WC_RSA_PSS case rsa_pss_sa_algo: authStr = "RSA-PSS"; break; #endif #endif #ifndef NO_DSA case dsa_sa_algo: authStr = "DSA"; break; #endif #ifdef HAVE_ECC case ecc_dsa_sa_algo: authStr = "ECDSA"; break; #endif #ifdef HAVE_ED25519 case ed25519_sa_algo: authStr = "Ed25519"; break; #endif #ifdef HAVE_ED448 case ed448_sa_algo: authStr = "Ed448"; break; #endif default: authStr = "unknown"; break; } return authStr; } static WC_INLINE const char* wolfssl_cipher_to_string(int cipher, int key_size) { const char* encStr; (void)key_size; switch (cipher) { case wolfssl_cipher_null: encStr = "None"; break; #ifndef NO_RC4 case wolfssl_rc4: encStr = "RC4(128)"; break; #endif #ifndef NO_DES3 case wolfssl_triple_des: encStr = "3DES(168)"; break; #endif #ifndef NO_AES case wolfssl_aes: if (key_size == 128) encStr = "AES(128)"; else if (key_size == 256) encStr = "AES(256)"; else encStr = "AES(?)"; break; #ifdef HAVE_AESGCM case wolfssl_aes_gcm: if (key_size == 128) encStr = "AESGCM(128)"; else if (key_size == 256) encStr = "AESGCM(256)"; else encStr = "AESGCM(?)"; break; #endif #ifdef HAVE_AESCCM case wolfssl_aes_ccm: if (key_size == 128) encStr = "AESCCM(128)"; else if (key_size == 256) encStr = "AESCCM(256)"; else encStr = "AESCCM(?)"; break; #endif #endif #ifdef HAVE_CHACHA case wolfssl_chacha: encStr = "CHACHA20/POLY1305(256)"; break; #endif #ifdef HAVE_CAMELLIA case wolfssl_camellia: if (key_size == 128) encStr = "Camellia(128)"; else if (key_size == 256) encStr = "Camellia(256)"; else encStr = "Camellia(?)"; break; #endif default: encStr = "unknown"; break; } return encStr; } static WC_INLINE const char* wolfssl_mac_to_string(int mac) { const char* macStr; switch (mac) { case no_mac: macStr = "None"; break; #ifndef NO_MD5 case md5_mac: macStr = "MD5"; break; #endif #ifndef NO_SHA case sha_mac: macStr = "SHA1"; break; #endif #ifdef HAVE_SHA224 case sha224_mac: macStr = "SHA224"; break; #endif #ifndef NO_SHA256 case sha256_mac: macStr = "SHA256"; break; #endif #ifdef HAVE_SHA384 case sha384_mac: macStr = "SHA384"; break; #endif #ifdef HAVE_SHA512 case sha512_mac: macStr = "SHA512"; break; #endif default: macStr = "unknown"; break; } return macStr; } char* wolfSSL_CIPHER_description(const WOLFSSL_CIPHER* cipher, char* in, int len) { char *ret = in; const char *keaStr, *authStr, *encStr, *macStr; size_t strLen; WOLFSSL_ENTER("wolfSSL_CIPHER_description"); if (cipher == NULL || in == NULL) return NULL; #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) /* if cipher is in the stack from wolfSSL_get_ciphers_compat then * Return the description based on cipher_names[cipher->offset] */ if (cipher->in_stack == TRUE) { wolfSSL_sk_CIPHER_description((WOLFSSL_CIPHER*)cipher); XSTRNCPY(in,cipher->description,len); return ret; } #endif /* Get the cipher description based on the SSL session cipher */ keaStr = wolfssl_kea_to_string(cipher->ssl->specs.kea); authStr = wolfssl_sigalg_to_string(cipher->ssl->specs.sig_algo); encStr = wolfssl_cipher_to_string(cipher->ssl->specs.bulk_cipher_algorithm, cipher->ssl->specs.key_size); macStr = wolfssl_mac_to_string(cipher->ssl->specs.mac_algorithm); /* Build up the string by copying onto the end. */ XSTRNCPY(in, wolfSSL_CIPHER_get_name(cipher), len); in[len-1] = '\0'; strLen = XSTRLEN(in); len -= (int)strLen; in += strLen; XSTRNCPY(in, " ", len); in[len-1] = '\0'; strLen = XSTRLEN(in); len -= (int)strLen; in += strLen; XSTRNCPY(in, wolfSSL_get_version(cipher->ssl), len); in[len-1] = '\0'; strLen = XSTRLEN(in); len -= (int)strLen; in += strLen; XSTRNCPY(in, " Kx=", len); in[len-1] = '\0'; strLen = XSTRLEN(in); len -= (int)strLen; in += strLen; XSTRNCPY(in, keaStr, len); in[len-1] = '\0'; strLen = XSTRLEN(in); len -= (int)strLen; in += strLen; XSTRNCPY(in, " Au=", len); in[len-1] = '\0'; strLen = XSTRLEN(in); len -= (int)strLen; in += strLen; XSTRNCPY(in, authStr, len); in[len-1] = '\0'; strLen = XSTRLEN(in); len -= (int)strLen; in += strLen; XSTRNCPY(in, " Enc=", len); in[len-1] = '\0'; strLen = XSTRLEN(in); len -= (int)strLen; in += strLen; XSTRNCPY(in, encStr, len); in[len-1] = '\0'; strLen = XSTRLEN(in); len -= (int)strLen; in += strLen; XSTRNCPY(in, " Mac=", len); in[len-1] = '\0'; strLen = XSTRLEN(in); len -= (int)strLen; in += strLen; XSTRNCPY(in, macStr, len); in[len-1] = '\0'; return ret; } #ifndef NO_WOLFSSL_STUB int wolfSSL_OCSP_parse_url(char* url, char** host, char** port, char** path, int* ssl) { (void)url; (void)host; (void)port; (void)path; (void)ssl; WOLFSSL_STUB("OCSP_parse_url"); return 0; } #endif #ifndef NO_MD4 void wolfSSL_MD4_Init(WOLFSSL_MD4_CTX* md4) { /* make sure we have a big enough buffer */ typedef char ok[sizeof(md4->buffer) >= sizeof(Md4) ? 1 : -1]; (void) sizeof(ok); WOLFSSL_ENTER("MD4_Init"); wc_InitMd4((Md4*)md4); } void wolfSSL_MD4_Update(WOLFSSL_MD4_CTX* md4, const void* data, unsigned long len) { WOLFSSL_ENTER("MD4_Update"); wc_Md4Update((Md4*)md4, (const byte*)data, (word32)len); } void wolfSSL_MD4_Final(unsigned char* digest, WOLFSSL_MD4_CTX* md4) { WOLFSSL_ENTER("MD4_Final"); wc_Md4Final((Md4*)md4, digest); } #endif /* NO_MD4 */ #ifndef NO_WOLFSSL_STUB void wolfSSL_RAND_screen(void) { WOLFSSL_STUB("RAND_screen"); } #endif int wolfSSL_RAND_load_file(const char* fname, long len) { (void)fname; /* wolfCrypt provides enough entropy internally or will report error */ if (len == -1) return 1024; else return (int)len; } #ifndef NO_WOLFSSL_STUB WOLFSSL_COMP_METHOD* wolfSSL_COMP_zlib(void) { WOLFSSL_STUB("COMP_zlib"); return 0; } #endif #ifndef NO_WOLFSSL_STUB WOLFSSL_COMP_METHOD* wolfSSL_COMP_rle(void) { WOLFSSL_STUB("COMP_rle"); return 0; } #endif #ifndef NO_WOLFSSL_STUB int wolfSSL_COMP_add_compression_method(int method, void* data) { (void)method; (void)data; WOLFSSL_STUB("COMP_add_compression_method"); return 0; } #endif /* wolfSSL_set_dynlock_create_callback * CRYPTO_set_dynlock_create_callback has been deprecated since openSSL 1.0.1. * This function exists for compatibility purposes because wolfSSL satisfies * thread safety without relying on the callback. */ void wolfSSL_set_dynlock_create_callback(WOLFSSL_dynlock_value* (*f)( const char*, int)) { WOLFSSL_STUB("CRYPTO_set_dynlock_create_callback"); (void)f; } /* wolfSSL_set_dynlock_lock_callback * CRYPTO_set_dynlock_lock_callback has been deprecated since openSSL 1.0.1. * This function exists for compatibility purposes because wolfSSL satisfies * thread safety without relying on the callback. */ void wolfSSL_set_dynlock_lock_callback( void (*f)(int, WOLFSSL_dynlock_value*, const char*, int)) { WOLFSSL_STUB("CRYPTO_set_set_dynlock_lock_callback"); (void)f; } /* wolfSSL_set_dynlock_destroy_callback * CRYPTO_set_dynlock_destroy_callback has been deprecated since openSSL 1.0.1. * This function exists for compatibility purposes because wolfSSL satisfies * thread safety without relying on the callback. */ void wolfSSL_set_dynlock_destroy_callback( void (*f)(WOLFSSL_dynlock_value*, const char*, int)) { WOLFSSL_STUB("CRYPTO_set_set_dynlock_destroy_callback"); (void)f; } #endif /* OPENSSL_EXTRA */ #ifdef OPENSSL_EXTRA #ifndef NO_CERTS #if !defined(NO_ASN) && !defined(NO_PWDBASED) /* Copies unencrypted DER key buffer into "der". If "der" is null then the size * of buffer needed is returned. If *der == NULL then it allocates a buffer. * NOTE: This also advances the "der" pointer to be at the end of buffer. * * Returns size of key buffer on success */ int wolfSSL_i2d_PrivateKey(const WOLFSSL_EVP_PKEY* key, unsigned char** der) { return wolfSSL_EVP_PKEY_get_der(key, der); } int wolfSSL_i2d_PublicKey(const WOLFSSL_EVP_PKEY *key, unsigned char **der) { return wolfSSL_EVP_PKEY_get_der(key, der); } #endif /* !NO_ASN && !NO_PWDBASED */ #endif /* !NO_CERTS */ #endif /* OPENSSL_EXTRA */ #ifdef OPENSSL_EXTRA /****************************************************************************** * wolfSSL_CTX_set1_param - set a pointer to the SSL verification parameters * * RETURNS: * WOLFSSL_SUCCESS on success, otherwise returns WOLFSSL_FAILURE * Note: Returns WOLFSSL_SUCCESS, in case either parameter is NULL, * same as openssl. */ int wolfSSL_CTX_set1_param(WOLFSSL_CTX* ctx, WOLFSSL_X509_VERIFY_PARAM *vpm) { if (ctx == NULL || vpm == NULL) return WOLFSSL_SUCCESS; return wolfSSL_X509_VERIFY_PARAM_set1(ctx->param, vpm); } /****************************************************************************** * wolfSSL_CTX/_get0_param - return a pointer to the SSL verification parameters * * RETURNS: * returns pointer to the SSL verification parameters on success, * otherwise returns NULL */ WOLFSSL_X509_VERIFY_PARAM* wolfSSL_CTX_get0_param(WOLFSSL_CTX* ctx) { if (ctx == NULL) { return NULL; } return ctx->param; } WOLFSSL_X509_VERIFY_PARAM* wolfSSL_get0_param(WOLFSSL* ssl) { if (ssl == NULL) { return NULL; } return ssl->param; } #endif /* OPENSSL_EXTRA */ #if defined(OPENSSL_EXTRA) int wolfSSL_i2d_ASN1_INTEGER(WOLFSSL_ASN1_INTEGER* a, unsigned char** out) { int ret = 0; word32 idx = 0; int len; int preAlloc = 1; WOLFSSL_ENTER("wolfSSL_i2d_ASN1_INTEGER"); if (a == NULL || a->data == NULL || a->length <= 0 || out == NULL) { WOLFSSL_MSG("Bad parameter."); ret = WOLFSSL_FATAL_ERROR; } if (ret == 0 && *out == NULL) { preAlloc = 0; *out = (unsigned char*)XMALLOC(a->length, NULL, DYNAMIC_TYPE_ASN1); if (*out == NULL) { WOLFSSL_MSG("Failed to allocate output buffer."); ret = WOLFSSL_FATAL_ERROR; } } if (ret == 0) { /* * A WOLFSSL_ASN1_INTEGER stores the DER buffer of the integer in its * "data" field, but it's only the magnitude of the number (i.e. the * sign isn't encoded). The "negative" field is 1 if the value should * be interpreted as negative and 0 otherwise. If the value is negative, * we need to output the 2's complement of the value in the DER output. */ XMEMCPY(*out, a->data, a->length); if (a->negative) { if (GetLength(a->data, &idx, &len, a->length) < 0) { ret = WOLFSSL_FATAL_ERROR; } else { ++idx; for (; (int)idx < a->length; ++idx) { (*out)[idx] = ~(*out)[idx]; } do { --idx; ++(*out)[idx]; } while ((*out)[idx] == 0); } } } if (ret == 0) { ret = a->length; if (preAlloc) { *out += a->length; } } WOLFSSL_LEAVE("wolfSSL_i2d_ASN1_INTEGER", ret); return ret; } WOLFSSL_ASN1_INTEGER* wolfSSL_d2i_ASN1_INTEGER(WOLFSSL_ASN1_INTEGER** a, const unsigned char** in, long inSz) { WOLFSSL_ASN1_INTEGER* ret = NULL; int err = 0; word32 idx = 0; int len; WOLFSSL_ENTER("wolfSSL_d2i_ASN1_INTEGER"); if (in == NULL || *in == NULL || inSz <= 0) { WOLFSSL_MSG("Bad parameter"); err = 1; } if (err == 0 && (*in)[0] != ASN_INTEGER) { WOLFSSL_MSG("Tag doesn't indicate integer type."); err = 1; } if (err == 0) { ret = wolfSSL_ASN1_INTEGER_new(); if (ret == NULL) { err = 1; } else { ret->type = V_ASN1_INTEGER; } } if (err == 0 && inSz > (long)sizeof(ret->intData)) { ret->data = (unsigned char*)XMALLOC(inSz, NULL, DYNAMIC_TYPE_ASN1); if (ret->data == NULL) { err = 1; } else { ret->isDynamic = 1; ret->dataMax = (word32)inSz; } } if (err == 0) { XMEMCPY(ret->data, *in, inSz); ret->length = (word32)inSz; /* Advance to the end of the length field.*/ if (GetLength(*in, &idx, &len, (word32)inSz) < 0) { err = 1; } else { /* See 2's complement comment in wolfSSL_d2i_ASN1_INTEGER. */ ret->negative = (*in)[idx+1] & 0x80; if (ret->negative) { ++idx; for (; (int)idx < inSz; ++idx) { ret->data[idx] = ~ret->data[idx]; } do { --idx; ++ret->data[idx]; } while (ret->data[idx] == 0); ret->type |= V_ASN1_NEG_INTEGER; } if (a != NULL) { *a = ret; } } } if (err != 0) { wolfSSL_ASN1_INTEGER_free(ret); ret = NULL; } return ret; } #endif /* OPENSSL_EXTRA */ #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) /* Used to create a new WOLFSSL_ASN1_INTEGER structure. * returns a pointer to new structure on success and NULL on failure */ WOLFSSL_ASN1_INTEGER* wolfSSL_ASN1_INTEGER_new(void) { WOLFSSL_ASN1_INTEGER* a; a = (WOLFSSL_ASN1_INTEGER*)XMALLOC(sizeof(WOLFSSL_ASN1_INTEGER), NULL, DYNAMIC_TYPE_OPENSSL); if (a == NULL) { return NULL; } XMEMSET(a, 0, sizeof(WOLFSSL_ASN1_INTEGER)); a->data = a->intData; a->isDynamic = 0; a->dataMax = WOLFSSL_ASN1_INTEGER_MAX; a->length = 0; return a; } /* free's internal elements of WOLFSSL_ASN1_INTEGER and free's "in" itself */ void wolfSSL_ASN1_INTEGER_free(WOLFSSL_ASN1_INTEGER* in) { if (in != NULL) { if (in->isDynamic) { XFREE(in->data, NULL, DYNAMIC_TYPE_OPENSSL); } XFREE(in, NULL, DYNAMIC_TYPE_OPENSSL); } } /* Duplicate all WOLFSSL_ASN1_INTEGER members from src to dup * src : WOLFSSL_ASN1_INTEGER to duplicate * Returns pointer to duplicate WOLFSSL_ASN1_INTEGER */ WOLFSSL_ASN1_INTEGER* wolfSSL_ASN1_INTEGER_dup(const WOLFSSL_ASN1_INTEGER* src) { WOLFSSL_ASN1_INTEGER* copy; WOLFSSL_ENTER("wolfSSL_ASN1_INTEGER_dup"); if (!src) return NULL; copy = wolfSSL_ASN1_INTEGER_new(); if (copy == NULL) return NULL; copy->negative = src->negative; copy->dataMax = src->dataMax; copy->isDynamic = src->isDynamic; #if defined(OPENSSL_ALL) || defined(WOLFSSL_QT) copy->length = src->length; #endif XSTRNCPY((char*)copy->intData,(const char*)src->intData,WOLFSSL_ASN1_INTEGER_MAX); if (copy->isDynamic && src->data && copy->dataMax) { copy->data = (unsigned char*) XMALLOC(src->dataMax,NULL,DYNAMIC_TYPE_OPENSSL); if (copy->data == NULL) { wolfSSL_ASN1_INTEGER_free(copy); return NULL; } XMEMCPY(copy->data, src->data, copy->dataMax); } return copy; } /* sets the value of WOLFSSL_ASN1_INTEGER a to the long value v. */ int wolfSSL_ASN1_INTEGER_set(WOLFSSL_ASN1_INTEGER *a, long v) { int ret = WOLFSSL_SUCCESS; /* return 1 for success and 0 for failure */ int j; unsigned int i = 0; unsigned char tmp[sizeof(long)+1] = {0}; int pad = 0; if (a != NULL) { /* dynamically create data buffer, +2 for type and length */ a->data = (unsigned char*)XMALLOC((sizeof(long)+1) + 2, NULL, DYNAMIC_TYPE_OPENSSL); if (a->data == NULL) { wolfSSL_ASN1_INTEGER_free(a); ret = WOLFSSL_FAILURE; } else { a->dataMax = (int)(sizeof(long)+1) + 2; a->isDynamic = 1; } } else { /* Invalid parameter */ ret = WOLFSSL_FAILURE; } if (ret != WOLFSSL_FAILURE) { /* Set type */ a->data[i++] = ASN_INTEGER; /* Check for negative */ if (v < 0) { a->negative = 1; v *= -1; } /* Create char buffer */ for (j = 0; j < (int)sizeof(long); j++) { if (v == 0) { break; } tmp[j] = (unsigned char)(v & 0xff); v >>= 8; } /* 0 pad to indicate positive number when top bit set. */ if ((!a->negative) && (j > 0) && (tmp[j-1] & 0x80)) { pad = 1; } /* Set length */ a->data[i++] = (unsigned char)(((j == 0) ? ++j : j) + pad); /* +2 for type and length */ a->length = j + pad + 2; /* Add padding if required. */ if (pad) { a->data[i++] = 0; } /* Copy to data */ for (; j > 0; j--) { a->data[i++] = tmp[j-1]; } } return ret; } #endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */ #if defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(WOLFSSL_NGINX) || \ defined(WOLFSSL_HAPROXY) || defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) #ifndef NO_ASN_TIME #ifndef NO_BIO int wolfSSL_ASN1_TIME_print(WOLFSSL_BIO* bio, const WOLFSSL_ASN1_TIME* asnTime) { char buf[MAX_TIME_STRING_SZ]; int ret = WOLFSSL_SUCCESS; WOLFSSL_ENTER("wolfSSL_ASN1_TIME_print"); if (bio == NULL || asnTime == NULL) { WOLFSSL_MSG("NULL function argument"); return WOLFSSL_FAILURE; } if (wolfSSL_ASN1_TIME_to_string((WOLFSSL_ASN1_TIME*)asnTime, buf, sizeof(buf)) == NULL) { XMEMSET(buf, 0, MAX_TIME_STRING_SZ); XSTRNCPY(buf, "Bad time value", sizeof(buf)-1); ret = WOLFSSL_FAILURE; } if (wolfSSL_BIO_write(bio, buf, (int)XSTRLEN(buf)) <= 0) { WOLFSSL_MSG("Unable to write to bio"); return WOLFSSL_FAILURE; } return ret; } #endif /* !NO_BIO */ char* wolfSSL_ASN1_TIME_to_string(WOLFSSL_ASN1_TIME* t, char* buf, int len) { WOLFSSL_ENTER("wolfSSL_ASN1_TIME_to_string"); if (t == NULL || buf == NULL || len < 5) { WOLFSSL_MSG("Bad argument"); return NULL; } if (t->length > len) { WOLFSSL_MSG("Length of date is longer then buffer"); return NULL; } if (!GetTimeString(t->data, t->type, buf, len)) { return NULL; } return buf; } /* Converts a WOLFSSL_ASN1_TIME to a struct tm. Returns WOLFSSL_SUCCESS on * success and WOLFSSL_FAILURE on failure. */ static int Asn1TimeToTm(WOLFSSL_ASN1_TIME* asnTime, struct tm* tm) { unsigned char* asn1TimeBuf; int asn1TimeBufLen; int i = 0; int bytesNeeded = 11; if (asnTime == NULL) { WOLFSSL_MSG("asnTime is NULL"); return WOLFSSL_FAILURE; } if (tm == NULL) { WOLFSSL_MSG("tm is NULL"); return WOLFSSL_FAILURE; } asn1TimeBuf = wolfSSL_ASN1_TIME_get_data(asnTime); if (asn1TimeBuf == NULL) { WOLFSSL_MSG("Failed to get WOLFSSL_ASN1_TIME buffer."); return WOLFSSL_FAILURE; } asn1TimeBufLen = wolfSSL_ASN1_TIME_get_length(asnTime); if (asn1TimeBufLen <= 0) { WOLFSSL_MSG("Failed to get WOLFSSL_ASN1_TIME buffer length."); return WOLFSSL_FAILURE; } XMEMSET(tm, 0, sizeof(struct tm)); /* Convert ASN1_time to struct tm */ /* Check type */ if (asnTime->type == ASN_UTC_TIME) { /* 2-digit year */ bytesNeeded += 2; if (bytesNeeded > asn1TimeBufLen) { WOLFSSL_MSG("WOLFSSL_ASN1_TIME buffer length is invalid."); return WOLFSSL_FAILURE; } if (asn1TimeBuf[bytesNeeded-1] != 'Z') { WOLFSSL_MSG("Expecting UTC time."); return WOLFSSL_FAILURE; } tm->tm_year = (asn1TimeBuf[i] - '0') * 10; i++; tm->tm_year += asn1TimeBuf[i] - '0'; i++; if (tm->tm_year < 70) { tm->tm_year += 100; } } else if (asnTime->type == ASN_GENERALIZED_TIME) { /* 4-digit year */ bytesNeeded += 4; if (bytesNeeded > asn1TimeBufLen) { WOLFSSL_MSG("WOLFSSL_ASN1_TIME buffer length is invalid."); return WOLFSSL_FAILURE; } if (asn1TimeBuf[bytesNeeded-1] != 'Z') { WOLFSSL_MSG("Expecting UTC time."); return WOLFSSL_FAILURE; } tm->tm_year = (asn1TimeBuf[i] - '0') * 1000; i++; tm->tm_year += (asn1TimeBuf[i] - '0') * 100; i++; tm->tm_year += (asn1TimeBuf[i] - '0') * 10; i++; tm->tm_year += asn1TimeBuf[i] - '0'; i++; tm->tm_year -= 1900; } else { WOLFSSL_MSG("asnTime->type is invalid."); return WOLFSSL_FAILURE; } tm->tm_mon = (asn1TimeBuf[i] - '0') * 10; i++; tm->tm_mon += (asn1TimeBuf[i] - '0') - 1; i++; /* January is 0 not 1 */ tm->tm_mday = (asn1TimeBuf[i] - '0') * 10; i++; tm->tm_mday += (asn1TimeBuf[i] - '0'); i++; tm->tm_hour = (asn1TimeBuf[i] - '0') * 10; i++; tm->tm_hour += (asn1TimeBuf[i] - '0'); i++; tm->tm_min = (asn1TimeBuf[i] - '0') * 10; i++; tm->tm_min += (asn1TimeBuf[i] - '0'); i++; tm->tm_sec = (asn1TimeBuf[i] - '0') * 10; i++; tm->tm_sec += (asn1TimeBuf[i] - '0'); #ifdef XMKTIME /* Call XMKTIME on tm to get the tm_wday and tm_yday fields populated. */ XMKTIME(tm); #endif return WOLFSSL_SUCCESS; } int wolfSSL_ASN1_TIME_to_tm(const WOLFSSL_ASN1_TIME* asnTime, struct tm* tm) { time_t currentTime; struct tm *tmpTs; #if defined(NEED_TMP_TIME) /* for use with gmtime_r */ struct tm tmpTimeStorage; tmpTs = &tmpTimeStorage; #else tmpTs = NULL; #endif (void)tmpTs; WOLFSSL_ENTER("wolfSSL_ASN1_TIME_to_tm"); /* If asnTime is NULL, then the current time is converted. */ if (asnTime == NULL) { if (tm == NULL) { WOLFSSL_MSG("asnTime and tm are both NULL"); return WOLFSSL_FAILURE; } currentTime = wc_Time(0); if (currentTime <= 0) { WOLFSSL_MSG("Failed to get current time."); return WOLFSSL_FAILURE; } tm = XGMTIME(¤tTime, tmpTs); if (tm == NULL) { WOLFSSL_MSG("Failed to convert current time to UTC."); return WOLFSSL_FAILURE; } return WOLFSSL_SUCCESS; } /* If tm is NULL this function performs a format check on asnTime only. */ if (tm == NULL) { return wolfSSL_ASN1_TIME_check(asnTime); } return Asn1TimeToTm((WOLFSSL_ASN1_TIME*)asnTime, tm); } #endif /* !NO_ASN_TIME */ #endif /* WOLFSSL_MYSQL_COMPATIBLE || WOLFSSL_NGINX || WOLFSSL_HAPROXY || OPENSSL_EXTRA*/ #ifdef OPENSSL_EXTRA int wolfSSL_ASN1_INTEGER_cmp(const WOLFSSL_ASN1_INTEGER* a, const WOLFSSL_ASN1_INTEGER* b) { int ret = 0; WOLFSSL_ENTER("wolfSSL_ASN1_INTEGER_cmp"); if (a == NULL || b == NULL) { WOLFSSL_MSG("Bad parameter."); ret = WOLFSSL_FATAL_ERROR; } if (ret == 0 && ((a->length != b->length) || ((a->negative == 0) != (b->negative == 0)))) { ret = WOLFSSL_FATAL_ERROR; } if (ret == 0) { ret = XMEMCMP(a->data, b->data, a->length); } WOLFSSL_LEAVE("wolfSSL_ASN1_INTEGER_cmp", ret); return ret; } long wolfSSL_ASN1_INTEGER_get(const WOLFSSL_ASN1_INTEGER* a) { long ret = 1; WOLFSSL_BIGNUM* bn = NULL; WOLFSSL_ENTER("ASN1_INTEGER_get"); if (a == NULL) { /* OpenSSL returns 0 when a is NULL and -1 if there is an error. Quoting * the documentation: * * "ASN1_INTEGER_get() also returns the value of a but it returns 0 if a * is NULL and -1 on error (which is ambiguous because -1 is a * legitimate value for an ASN1_INTEGER). New applications should use * ASN1_INTEGER_get_int64() instead." * */ ret = 0; } if (ret > 0) { bn = wolfSSL_ASN1_INTEGER_to_BN(a, NULL); if (bn == NULL) { ret = -1; } } if (ret > 0) { ret = wolfSSL_BN_get_word(bn); if (a->negative == 1) { ret = -ret; } } if (bn != NULL) { wolfSSL_BN_free(bn); } WOLFSSL_LEAVE("ASN1_INTEGER_get", (int)ret); return ret; } #endif /* OPENSSL_EXTRA */ #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) /* Gets an index to store SSL structure at. * * Returns positive index on success and negative values on failure */ int wolfSSL_get_ex_data_X509_STORE_CTX_idx(void) { WOLFSSL_ENTER("wolfSSL_get_ex_data_X509_STORE_CTX_idx"); /* store SSL at index 0 */ return 0; } #endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */ #ifdef OPENSSL_EXTRA /* Sets a function callback that will send information about the state of all * WOLFSSL objects that have been created by the WOLFSSL_CTX structure passed * in. * * ctx WOLFSSL_CTX structure to set callback function in * f callback function to use */ void wolfSSL_CTX_set_info_callback(WOLFSSL_CTX* ctx, void (*f)(const WOLFSSL* ssl, int type, int val)) { WOLFSSL_ENTER("wolfSSL_CTX_set_info_callback"); if (ctx == NULL) { WOLFSSL_MSG("Bad function argument"); } else { ctx->CBIS = f; } } unsigned long wolfSSL_ERR_peek_error(void) { WOLFSSL_ENTER("wolfSSL_ERR_peek_error"); return wolfSSL_ERR_peek_error_line_data(NULL, NULL, NULL, NULL); } int wolfSSL_ERR_GET_LIB(unsigned long err) { unsigned long value; 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: case PEM_R_BAD_DECRYPT: return ERR_LIB_PEM; case EVP_R_BAD_DECRYPT: case EVP_R_BN_DECODE_ERROR: case EVP_R_DECODE_ERROR: case EVP_R_PRIVATE_KEY_DECODE_ERROR: return ERR_LIB_EVP; case ASN1_R_HEADER_TOO_LONG: return ERR_LIB_ASN1; default: return 0; } } /* This function is to find global error values that are the same through out * all library version. With wolfSSL having only one set of error codes the * return value is pretty straight forward. The only thing needed is all wolfSSL * error values are typically negative. * * Returns the error reason */ int wolfSSL_ERR_GET_REASON(unsigned long err) { int ret = (int)err; WOLFSSL_ENTER("wolfSSL_ERR_GET_REASON"); #if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) /* 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)) return ASN1_R_HEADER_TOO_LONG; #endif /* check if error value is in range of wolfSSL errors */ ret = 0 - ret; /* setting as negative value */ /* wolfCrypt range is less than MAX (-100) wolfSSL range is MIN (-300) and lower */ if (ret < MAX_CODE_E && ret > MIN_CODE_E) { return ret; } else { WOLFSSL_MSG("Not in range of typical error values"); ret = (int)err; } return ret; } /* returns a string that describes the alert * * alertID the alert value to look up */ const char* wolfSSL_alert_type_string_long(int alertID) { WOLFSSL_ENTER("wolfSSL_alert_type_string_long"); return AlertTypeToString(alertID); } const char* wolfSSL_alert_desc_string_long(int alertID) { WOLFSSL_ENTER("wolfSSL_alert_desc_string_long"); return AlertTypeToString(alertID); } /* Gets the current state of the WOLFSSL structure * * ssl WOLFSSL structure to get state of * * Returns a human readable string of the WOLFSSL structure state */ const char* wolfSSL_state_string_long(const WOLFSSL* ssl) { static const char* OUTPUT_STR[14][6][3] = { { {"SSLv3 Initialization","SSLv3 Initialization","SSLv3 Initialization"}, {"TLSv1 Initialization","TLSv2 Initialization","TLSv2 Initialization"}, {"TLSv1_1 Initialization","TLSv1_1 Initialization","TLSv1_1 Initialization"}, {"TLSv1_2 Initialization","TLSv1_2 Initialization","TLSv1_2 Initialization"}, {"DTLSv1 Initialization","DTLSv1 Initialization","DTLSv1 Initialization"}, {"DTLSv1_2 Initialization","DTLSv1_2 Initialization","DTLSv1_2 Initialization"}, }, { {"SSLv3 read Server Hello Verify Request", "SSLv3 write Server Hello Verify Request", "SSLv3 Server Hello Verify Request"}, {"TLSv1 read Server Hello Verify Request", "TLSv1 write Server Hello Verify Request", "TLSv1 Server Hello Verify Request"}, {"TLSv1_1 read Server Hello Verify Request", "TLSv1_1 write Server Hello Verify Request", "TLSv1_1 Server Hello Verify Request"}, {"TLSv1_2 read Server Hello Verify Request", "TLSv1_2 write Server Hello Verify Request", "TLSv1_2 Server Hello Verify Request"}, {"DTLSv1 read Server Hello Verify Request", "DTLSv1 write Server Hello Verify Request", "DTLSv1 Server Hello Verify Request"}, {"DTLSv1_2 read Server Hello Verify Request", "DTLSv1_2 write Server Hello Verify Request", "DTLSv1_2 Server Hello Verify Request"}, }, { {"SSLv3 read Server Hello", "SSLv3 write Server Hello", "SSLv3 Server Hello"}, {"TLSv1 read Server Hello", "TLSv1 write Server Hello", "TLSv1 Server Hello"}, {"TLSv1_1 read Server Hello", "TLSv1_1 write Server Hello", "TLSv1_1 Server Hello"}, {"TLSv1_2 read Server Hello", "TLSv1_2 write Server Hello", "TLSv1_2 Server Hello"}, {"DTLSv1 read Server Hello", "DTLSv1 write Server Hello", "DTLSv1 Server Hello"}, {"DTLSv1_2 read Server Hello" "DTLSv1_2 write Server Hello", "DTLSv1_2 Server Hello", }, }, { {"SSLv3 read Server Session Ticket", "SSLv3 write Server Session Ticket", "SSLv3 Server Session Ticket"}, {"TLSv1 read Server Session Ticket", "TLSv1 write Server Session Ticket", "TLSv1 Server Session Ticket"}, {"TLSv1_1 read Server Session Ticket", "TLSv1_1 write Server Session Ticket", "TLSv1_1 Server Session Ticket"}, {"TLSv1_2 read Server Session Ticket", "TLSv1_2 write Server Session Ticket", "TLSv1_2 Server Session Ticket"}, {"DTLSv1 read Server Session Ticket", "DTLSv1 write Server Session Ticket", "DTLSv1 Server Session Ticket"}, {"DTLSv1_2 read Server Session Ticket", "DTLSv1_2 write Server Session Ticket", "DTLSv1_2 Server Session Ticket"}, }, { {"SSLv3 read Server Cert", "SSLv3 write Server Cert", "SSLv3 Server Cert"}, {"TLSv1 read Server Cert", "TLSv1 write Server Cert", "TLSv1 Server Cert"}, {"TLSv1_1 read Server Cert", "TLSv1_1 write Server Cert", "TLSv1_1 Server Cert"}, {"TLSv1_2 read Server Cert", "TLSv1_2 write Server Cert", "TLSv1_2 Server Cert"}, {"DTLSv1 read Server Cert", "DTLSv1 write Server Cert", "DTLSv1 Server Cert"}, {"DTLSv1_2 read Server Cert", "DTLSv1_2 write Server Cert", "DTLSv1_2 Server Cert"}, }, { {"SSLv3 read Server Key Exchange", "SSLv3 write Server Key Exchange", "SSLv3 Server Key Exchange"}, {"TLSv1 read Server Key Exchange", "TLSv1 write Server Key Exchange", "TLSv1 Server Key Exchange"}, {"TLSv1_1 read Server Key Exchange", "TLSv1_1 write Server Key Exchange", "TLSv1_1 Server Key Exchange"}, {"TLSv1_2 read Server Key Exchange", "TLSv1_2 write Server Key Exchange", "TLSv1_2 Server Key Exchange"}, {"DTLSv1 read Server Key Exchange", "DTLSv1 write Server Key Exchange", "DTLSv1 Server Key Exchange"}, {"DTLSv1_2 read Server Key Exchange", "DTLSv1_2 write Server Key Exchange", "DTLSv1_2 Server Key Exchange"}, }, { {"SSLv3 read Server Hello Done", "SSLv3 write Server Hello Done", "SSLv3 Server Hello Done"}, {"TLSv1 read Server Hello Done", "TLSv1 write Server Hello Done", "TLSv1 Server Hello Done"}, {"TLSv1_1 read Server Hello Done", "TLSv1_1 write Server Hello Done", "TLSv1_1 Server Hello Done"}, {"TLSv1_2 read Server Hello Done", "TLSv1_2 write Server Hello Done", "TLSv1_2 Server Hello Done"}, {"DTLSv1 read Server Hello Done", "DTLSv1 write Server Hello Done", "DTLSv1 Server Hello Done"}, {"DTLSv1_2 read Server Hello Done", "DTLSv1_2 write Server Hello Done", "DTLSv1_2 Server Hello Done"}, }, { {"SSLv3 read Server Change CipherSpec", "SSLv3 write Server Change CipherSpec", "SSLv3 Server Change CipherSpec"}, {"TLSv1 read Server Change CipherSpec", "TLSv1 write Server Change CipherSpec", "TLSv1 Server Change CipherSpec"}, {"TLSv1_1 read Server Change CipherSpec", "TLSv1_1 write Server Change CipherSpec", "TLSv1_1 Server Change CipherSpec"}, {"TLSv1_2 read Server Change CipherSpec", "TLSv1_2 write Server Change CipherSpec", "TLSv1_2 Server Change CipherSpec"}, {"DTLSv1 read Server Change CipherSpec", "DTLSv1 write Server Change CipherSpec", "DTLSv1 Server Change CipherSpec"}, {"DTLSv1_2 read Server Change CipherSpec", "DTLSv1_2 write Server Change CipherSpec", "DTLSv1_2 Server Change CipherSpec"}, }, { {"SSLv3 read Server Finished", "SSLv3 write Server Finished", "SSLv3 Server Finished"}, {"TLSv1 read Server Finished", "TLSv1 write Server Finished", "TLSv1 Server Finished"}, {"TLSv1_1 read Server Finished", "TLSv1_1 write Server Finished", "TLSv1_1 Server Finished"}, {"TLSv1_2 read Server Finished", "TLSv1_2 write Server Finished", "TLSv1_2 Server Finished"}, {"DTLSv1 read Server Finished", "DTLSv1 write Server Finished", "DTLSv1 Server Finished"}, {"DTLSv1_2 read Server Finished", "DTLSv1_2 write Server Finished", "DTLSv1_2 Server Finished"}, }, { {"SSLv3 read Client Hello", "SSLv3 write Client Hello", "SSLv3 Client Hello"}, {"TLSv1 read Client Hello", "TLSv1 write Client Hello", "TLSv1 Client Hello"}, {"TLSv1_1 read Client Hello", "TLSv1_1 write Client Hello", "TLSv1_1 Client Hello"}, {"TLSv1_2 read Client Hello", "TLSv1_2 write Client Hello", "TLSv1_2 Client Hello"}, {"DTLSv1 read Client Hello", "DTLSv1 write Client Hello", "DTLSv1 Client Hello"}, {"DTLSv1_2 read Client Hello", "DTLSv1_2 write Client Hello", "DTLSv1_2 Client Hello"}, }, { {"SSLv3 read Client Key Exchange", "SSLv3 write Client Key Exchange", "SSLv3 Client Key Exchange"}, {"TLSv1 read Client Key Exchange", "TLSv1 write Client Key Exchange", "TLSv1 Client Key Exchange"}, {"TLSv1_1 read Client Key Exchange", "TLSv1_1 write Client Key Exchange", "TLSv1_1 Client Key Exchange"}, {"TLSv1_2 read Client Key Exchange", "TLSv1_2 write Client Key Exchange", "TLSv1_2 Client Key Exchange"}, {"DTLSv1 read Client Key Exchange", "DTLSv1 write Client Key Exchange", "DTLSv1 Client Key Exchange"}, {"DTLSv1_2 read Client Key Exchange", "DTLSv1_2 write Client Key Exchange", "DTLSv1_2 Client Key Exchange"}, }, { {"SSLv3 read Client Change CipherSpec", "SSLv3 write Client Change CipherSpec", "SSLv3 Client Change CipherSpec"}, {"TLSv1 read Client Change CipherSpec", "TLSv1 write Client Change CipherSpec", "TLSv1 Client Change CipherSpec"}, {"TLSv1_1 read Client Change CipherSpec", "TLSv1_1 write Client Change CipherSpec", "TLSv1_1 Client Change CipherSpec"}, {"TLSv1_2 read Client Change CipherSpec", "TLSv1_2 write Client Change CipherSpec", "TLSv1_2 Client Change CipherSpec"}, {"DTLSv1 read Client Change CipherSpec", "DTLSv1 write Client Change CipherSpec", "DTLSv1 Client Change CipherSpec"}, {"DTLSv1_2 read Client Change CipherSpec", "DTLSv1_2 write Client Change CipherSpec", "DTLSv1_2 Client Change CipherSpec"}, }, { {"SSLv3 read Client Finished", "SSLv3 write Client Finished", "SSLv3 Client Finished"}, {"TLSv1 read Client Finished", "TLSv1 write Client Finished", "TLSv1 Client Finished"}, {"TLSv1_1 read Client Finished", "TLSv1_1 write Client Finished", "TLSv1_1 Client Finished"}, {"TLSv1_2 read Client Finished", "TLSv1_2 write Client Finished", "TLSv1_2 Client Finished"}, {"DTLSv1 read Client Finished", "DTLSv1 write Client Finished", "DTLSv1 Client Finished"}, {"DTLSv1_2 read Client Finished", "DTLSv1_2 write Client Finished", "DTLSv1_2 Client Finished"}, }, { {"SSLv3 Handshake Done", "SSLv3 Handshake Done", "SSLv3 Handshake Done"}, {"TLSv1 Handshake Done", "TLSv1 Handshake Done", "TLSv1 Handshake Done"}, {"TLSv1_1 Handshake Done", "TLSv1_1 Handshake Done", "TLSv1_1 Handshake Done"}, {"TLSv1_2 Handshake Done", "TLSv1_2 Handshake Done", "TLSv1_2 Handshake Done"}, {"DTLSv1 Handshake Done", "DTLSv1 Handshake Done", "DTLSv1 Handshake Done"}, {"DTLSv1_2 Handshake Done" "DTLSv1_2 Handshake Done" "DTLSv1_2 Handshake Done"} } }; enum ProtocolVer { SSL_V3 = 0, TLS_V1, TLS_V1_1, TLS_V1_2, DTLS_V1, DTLS_V1_2, UNKNOWN = 100 }; enum IOMode { SS_READ = 0, SS_WRITE, SS_NEITHER }; enum SslState { ss_null_state = 0, ss_server_helloverify, ss_server_hello, ss_sessionticket, ss_server_cert, ss_server_keyexchange, ss_server_hellodone, ss_server_changecipherspec, ss_server_finished, ss_client_hello, ss_client_keyexchange, ss_client_changecipherspec, ss_client_finished, ss_handshake_done }; int protocol = 0; int cbmode = 0; int state = 0; WOLFSSL_ENTER("wolfSSL_state_string_long"); if (ssl == NULL) { WOLFSSL_MSG("Null argument passed in"); return NULL; } /* Get state of callback */ if (ssl->cbmode == SSL_CB_MODE_WRITE){ cbmode = SS_WRITE; } else if (ssl->cbmode == SSL_CB_MODE_READ){ cbmode = SS_READ; } else { cbmode = SS_NEITHER; } /* Get protocol version */ switch (ssl->version.major){ case SSLv3_MAJOR: switch (ssl->version.minor){ case TLSv1_MINOR: protocol = TLS_V1; break; case TLSv1_1_MINOR: protocol = TLS_V1_1; break; case TLSv1_2_MINOR: protocol = TLS_V1_2; break; case SSLv3_MINOR: protocol = SSL_V3; break; default: protocol = UNKNOWN; } break; case DTLS_MAJOR: switch (ssl->version.minor){ case DTLS_MINOR: protocol = DTLS_V1; break; case DTLSv1_2_MINOR: protocol = DTLS_V1_2; break; default: protocol = UNKNOWN; } break; default: protocol = UNKNOWN; } /* accept process */ if (ssl->cbmode == SSL_CB_MODE_READ){ state = ssl->cbtype; switch (state) { case hello_verify_request: state = ss_server_helloverify; break; case session_ticket: state = ss_sessionticket; break; case server_hello: state = ss_server_hello; break; case server_hello_done: state = ss_server_hellodone; break; case certificate: state = ss_server_cert; break; case server_key_exchange: state = ss_server_keyexchange; break; case client_hello: state = ss_client_hello; break; case client_key_exchange: state = ss_client_keyexchange; break; case finished: if (ssl->options.side == WOLFSSL_SERVER_END) state = ss_client_finished; else if (ssl->options.side == WOLFSSL_CLIENT_END) state = ss_server_finished; else { WOLFSSL_MSG("Unknown State"); state = ss_null_state; } break; default: WOLFSSL_MSG("Unknown State"); state = ss_null_state; } } else { /* Send process */ if (ssl->options.side == WOLFSSL_SERVER_END) state = ssl->options.serverState; else state = ssl->options.clientState; switch(state){ case SERVER_HELLOVERIFYREQUEST_COMPLETE: state = ss_server_helloverify; break; case SERVER_HELLO_COMPLETE: state = ss_server_hello; break; case SERVER_CERT_COMPLETE: state = ss_server_cert; break; case SERVER_KEYEXCHANGE_COMPLETE: state = ss_server_keyexchange; break; case SERVER_HELLODONE_COMPLETE: state = ss_server_hellodone; break; case SERVER_CHANGECIPHERSPEC_COMPLETE: state = ss_server_changecipherspec; break; case SERVER_FINISHED_COMPLETE: state = ss_server_finished; break; case CLIENT_HELLO_COMPLETE: state = ss_client_hello; break; case CLIENT_KEYEXCHANGE_COMPLETE: state = ss_client_keyexchange; break; case CLIENT_CHANGECIPHERSPEC_COMPLETE: state = ss_client_changecipherspec; break; case CLIENT_FINISHED_COMPLETE: state = ss_client_finished; break; case HANDSHAKE_DONE: state = ss_handshake_done; break; default: WOLFSSL_MSG("Unknown State"); state = ss_null_state; } } if (protocol == UNKNOWN) { WOLFSSL_MSG("Unknown protocol"); return ""; } else { return OUTPUT_STR[state][protocol][cbmode]; } } /* * Sets default PEM callback password if null is passed into * the callback parameter of a PEM_read_bio_* function. * * Returns callback phrase size on success or WOLFSSL_FAILURE otherwise. */ int wolfSSL_PEM_def_callback(char* name, int num, int w, void* key) { int sz; (void)w; WOLFSSL_ENTER("wolfSSL_PEM_def_callback"); /* We assume that the user passes a default password as userdata */ if (key) { sz = (int)XSTRLEN((const char*)key); sz = (sz > num) ? num : sz; XMEMCPY(name, key, sz); return sz; } else { WOLFSSL_MSG("Error, default password cannot be created."); return WOLFSSL_FAILURE; } } #endif /* OPENSSL_EXTRA */ static long wolf_set_options(long old_op, long op) { /* if SSL_OP_ALL then turn all bug workarounds on */ if ((op & WOLFSSL_OP_ALL) == WOLFSSL_OP_ALL) { WOLFSSL_MSG("\tSSL_OP_ALL"); } /* by default cookie exchange is on with DTLS */ if ((op & WOLFSSL_OP_COOKIE_EXCHANGE) == WOLFSSL_OP_COOKIE_EXCHANGE) { WOLFSSL_MSG("\tSSL_OP_COOKIE_EXCHANGE : on by default"); } if ((op & WOLFSSL_OP_NO_SSLv2) == WOLFSSL_OP_NO_SSLv2) { WOLFSSL_MSG("\tWOLFSSL_OP_NO_SSLv2 : wolfSSL does not support SSLv2"); } #ifdef SSL_OP_NO_TLSv1_3 if ((op & WOLFSSL_OP_NO_TLSv1_3) == WOLFSSL_OP_NO_TLSv1_3) { WOLFSSL_MSG("\tSSL_OP_NO_TLSv1_3"); } #endif if ((op & WOLFSSL_OP_NO_TLSv1_2) == WOLFSSL_OP_NO_TLSv1_2) { WOLFSSL_MSG("\tSSL_OP_NO_TLSv1_2"); } if ((op & WOLFSSL_OP_NO_TLSv1_1) == WOLFSSL_OP_NO_TLSv1_1) { WOLFSSL_MSG("\tSSL_OP_NO_TLSv1_1"); } if ((op & WOLFSSL_OP_NO_TLSv1) == WOLFSSL_OP_NO_TLSv1) { WOLFSSL_MSG("\tSSL_OP_NO_TLSv1"); } if ((op & WOLFSSL_OP_NO_SSLv3) == WOLFSSL_OP_NO_SSLv3) { WOLFSSL_MSG("\tSSL_OP_NO_SSLv3"); } if ((op & WOLFSSL_OP_CIPHER_SERVER_PREFERENCE) == WOLFSSL_OP_CIPHER_SERVER_PREFERENCE) { WOLFSSL_MSG("\tWOLFSSL_OP_CIPHER_SERVER_PREFERENCE"); } if ((op & WOLFSSL_OP_NO_COMPRESSION) == WOLFSSL_OP_NO_COMPRESSION) { #ifdef HAVE_LIBZ WOLFSSL_MSG("SSL_OP_NO_COMPRESSION"); #else WOLFSSL_MSG("SSL_OP_NO_COMPRESSION: compression not compiled in"); #endif } return old_op | op; } #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) long wolfSSL_set_options(WOLFSSL* ssl, long op) { word16 haveRSA = 1; word16 havePSK = 0; int keySz = 0; WOLFSSL_ENTER("wolfSSL_set_options"); if (ssl == NULL) { return 0; } ssl->options.mask = wolf_set_options(ssl->options.mask, op); #ifdef SSL_OP_NO_TLSv1_3 if ((ssl->options.mask & SSL_OP_NO_TLSv1_3) == SSL_OP_NO_TLSv1_3) { if (ssl->version.minor == TLSv1_3_MINOR) ssl->version.minor = TLSv1_2_MINOR; } #endif if ((ssl->options.mask & SSL_OP_NO_TLSv1_2) == SSL_OP_NO_TLSv1_2) { if (ssl->version.minor == TLSv1_2_MINOR) ssl->version.minor = TLSv1_1_MINOR; } if ((ssl->options.mask & SSL_OP_NO_TLSv1_1) == SSL_OP_NO_TLSv1_1) { if (ssl->version.minor == TLSv1_1_MINOR) ssl->version.minor = TLSv1_MINOR; } if ((ssl->options.mask & SSL_OP_NO_TLSv1) == SSL_OP_NO_TLSv1) { if (ssl->version.minor == TLSv1_MINOR) ssl->version.minor = SSLv3_MINOR; } if ((ssl->options.mask & WOLFSSL_OP_NO_COMPRESSION) == WOLFSSL_OP_NO_COMPRESSION) { #ifdef HAVE_LIBZ ssl->options.usingCompression = 0; #endif } /* in the case of a version change the cipher suites should be reset */ #ifndef NO_PSK havePSK = ssl->options.havePSK; #endif #ifdef NO_RSA haveRSA = 0; #endif #ifndef NO_CERTS keySz = ssl->buffers.keySz; #endif if (ssl->suites != NULL && ssl->options.side != WOLFSSL_NEITHER_END) InitSuites(ssl->suites, ssl->version, keySz, haveRSA, havePSK, ssl->options.haveDH, ssl->options.haveECDSAsig, ssl->options.haveECC, ssl->options.haveStaticECC, ssl->options.haveFalconSig, ssl->options.haveAnon, ssl->options.side); return ssl->options.mask; } long wolfSSL_get_options(const WOLFSSL* ssl) { WOLFSSL_ENTER("wolfSSL_get_options"); if(ssl == NULL) return WOLFSSL_FAILURE; return ssl->options.mask; } #endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */ #if defined(HAVE_SECURE_RENEGOTIATION) \ || defined(HAVE_SERVER_RENEGOTIATION_INFO) /* clears the counter for number of renegotiations done * returns the current count before it is cleared */ long wolfSSL_clear_num_renegotiations(WOLFSSL *s) { long total; WOLFSSL_ENTER("wolfSSL_clear_num_renegotiations"); if (s == NULL) return 0; total = s->secure_rene_count; s->secure_rene_count = 0; return total; } /* return the number of renegotiations since wolfSSL_new */ long wolfSSL_total_renegotiations(WOLFSSL *s) { WOLFSSL_ENTER("wolfSSL_total_renegotiations"); return wolfSSL_num_renegotiations(s); } /* return the number of renegotiations since wolfSSL_new */ long wolfSSL_num_renegotiations(WOLFSSL* s) { if (s == NULL) { return 0; } return s->secure_rene_count; } /* Is there a renegotiation currently in progress? */ int wolfSSL_SSL_renegotiate_pending(WOLFSSL *s) { return s && s->options.handShakeDone && s->options.handShakeState != HANDSHAKE_DONE ? 1 : 0; } #endif /* HAVE_SECURE_RENEGOTIATION || HAVE_SERVER_RENEGOTIATION_INFO */ #ifdef OPENSSL_EXTRA long wolfSSL_clear_options(WOLFSSL* ssl, long opt) { WOLFSSL_ENTER("SSL_clear_options"); if(ssl == NULL) return WOLFSSL_FAILURE; ssl->options.mask &= ~opt; return ssl->options.mask; } #ifdef HAVE_PK_CALLBACKS long wolfSSL_set_tlsext_debug_arg(WOLFSSL* ssl, void *arg) { if (ssl == NULL) { return WOLFSSL_FAILURE; } ssl->loggingCtx = arg; return WOLFSSL_SUCCESS; } #endif /* HAVE_PK_CALLBACKS */ #if defined(OPENSSL_ALL) || defined(WOLFSSL_HAPROXY) const unsigned char *SSL_SESSION_get0_id_context(const WOLFSSL_SESSION *sess, unsigned int *sid_ctx_length) { sess = ClientSessionToSession(sess); return wolfSSL_SESSION_get_id((WOLFSSL_SESSION *)sess, sid_ctx_length); } #endif /*** TBD ***/ #ifndef NO_WOLFSSL_STUB WOLFSSL_API int wolfSSL_sk_SSL_COMP_zero(WOLFSSL_STACK* st) { (void)st; WOLFSSL_STUB("wolfSSL_sk_SSL_COMP_zero"); /* wolfSSL_set_options(ssl, SSL_OP_NO_COMPRESSION); */ return WOLFSSL_FAILURE; } #endif #ifdef HAVE_CERTIFICATE_STATUS_REQUEST long wolfSSL_set_tlsext_status_type(WOLFSSL *s, int type) { WOLFSSL_ENTER("wolfSSL_set_tlsext_status_type"); if (s == NULL){ return BAD_FUNC_ARG; } if (type == TLSEXT_STATUSTYPE_ocsp){ int r = TLSX_UseCertificateStatusRequest(&s->extensions, (byte)type, 0, s, s->heap, s->devId); return (long)r; } else { WOLFSSL_MSG( "SSL_set_tlsext_status_type only supports TLSEXT_STATUSTYPE_ocsp type."); return SSL_FAILURE; } } long wolfSSL_get_tlsext_status_type(WOLFSSL *s) { TLSX* extension; if (s == NULL) return WOLFSSL_FATAL_ERROR; extension = TLSX_Find(s->extensions, TLSX_STATUS_REQUEST); return extension != NULL ? TLSEXT_STATUSTYPE_ocsp : WOLFSSL_FATAL_ERROR; } #endif /* HAVE_CERTIFICATE_STATUS_REQUEST */ #ifndef NO_WOLFSSL_STUB WOLFSSL_API long wolfSSL_get_tlsext_status_exts(WOLFSSL *s, void *arg) { (void)s; (void)arg; WOLFSSL_STUB("wolfSSL_get_tlsext_status_exts"); return WOLFSSL_FAILURE; } #endif /*** TBD ***/ #ifndef NO_WOLFSSL_STUB WOLFSSL_API long wolfSSL_set_tlsext_status_exts(WOLFSSL *s, void *arg) { (void)s; (void)arg; WOLFSSL_STUB("wolfSSL_set_tlsext_status_exts"); return WOLFSSL_FAILURE; } #endif /*** TBD ***/ #ifndef NO_WOLFSSL_STUB WOLFSSL_API long wolfSSL_get_tlsext_status_ids(WOLFSSL *s, void *arg) { (void)s; (void)arg; WOLFSSL_STUB("wolfSSL_get_tlsext_status_ids"); return WOLFSSL_FAILURE; } #endif /*** TBD ***/ #ifndef NO_WOLFSSL_STUB WOLFSSL_API long wolfSSL_set_tlsext_status_ids(WOLFSSL *s, void *arg) { (void)s; (void)arg; WOLFSSL_STUB("wolfSSL_set_tlsext_status_ids"); return WOLFSSL_FAILURE; } #endif /*** TBD ***/ #ifndef NO_WOLFSSL_STUB WOLFSSL_API int SSL_SESSION_set1_id(WOLFSSL_SESSION *s, const unsigned char *sid, unsigned int sid_len) { (void)s; (void)sid; (void)sid_len; WOLFSSL_STUB("SSL_SESSION_set1_id"); return WOLFSSL_FAILURE; } #endif #ifndef NO_WOLFSSL_STUB /*** TBD ***/ WOLFSSL_API int SSL_SESSION_set1_id_context(WOLFSSL_SESSION *s, const unsigned char *sid_ctx, unsigned int sid_ctx_len) { (void)s; (void)sid_ctx; (void)sid_ctx_len; WOLFSSL_STUB("SSL_SESSION_set1_id_context"); return WOLFSSL_FAILURE; } #endif #if defined(OPENSSL_ALL) || defined(WOLFSSL_APACHE_HTTPD) \ || defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_WPAS) /** * Set `a` in a smart way. * * @param a Object to set * @param type The type of object in value * @param value Object to set */ void wolfSSL_ASN1_TYPE_set(WOLFSSL_ASN1_TYPE *a, int type, void *value) { if (!a) { return; } switch (type) { case V_ASN1_NULL: a->value.ptr = (char *)value; break; case V_ASN1_SEQUENCE: a->value.asn1_string = (WOLFSSL_ASN1_STRING*)value; break; case V_ASN1_OBJECT: a->value.object = (WOLFSSL_ASN1_OBJECT*)value; break; case V_ASN1_UTCTIME: a->value.utctime = (WOLFSSL_ASN1_TIME*)value; break; case V_ASN1_GENERALIZEDTIME: a->value.generalizedtime = (WOLFSSL_ASN1_TIME*)value; break; default: WOLFSSL_MSG("Unknown or unsupported ASN1_TYPE"); return; } a->type = type; } #endif /* OPENSSL_ALL || WOLFSSL_APACHE_HTTPD || WOLFSSL_HAPROXY || WOLFSSL_WPAS */ #if defined(OPENSSL_ALL) || defined(WOLFSSL_APACHE_HTTPD) \ || defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_WPAS) \ || defined(OPENSSL_EXTRA) /** * Allocate a new WOLFSSL_ASN1_TYPE object. * * @return New zero'ed WOLFSSL_ASN1_TYPE object */ WOLFSSL_ASN1_TYPE* wolfSSL_ASN1_TYPE_new(void) { WOLFSSL_ASN1_TYPE* ret = (WOLFSSL_ASN1_TYPE*)XMALLOC(sizeof(WOLFSSL_ASN1_TYPE), NULL, DYNAMIC_TYPE_OPENSSL); if (!ret) return NULL; XMEMSET(ret, 0, sizeof(WOLFSSL_ASN1_TYPE)); return ret; } /** * Free WOLFSSL_ASN1_TYPE and all its members. * * @param at Object to free */ void wolfSSL_ASN1_TYPE_free(WOLFSSL_ASN1_TYPE* at) { if (at) { switch (at->type) { case V_ASN1_OBJECT: wolfSSL_ASN1_OBJECT_free(at->value.object); break; case V_ASN1_UTCTIME: #ifndef NO_ASN_TIME wolfSSL_ASN1_TIME_free(at->value.utctime); #endif break; case V_ASN1_GENERALIZEDTIME: #ifndef NO_ASN_TIME wolfSSL_ASN1_TIME_free(at->value.generalizedtime); #endif break; case V_ASN1_UTF8STRING: case V_ASN1_PRINTABLESTRING: case V_ASN1_T61STRING: case V_ASN1_IA5STRING: case V_ASN1_UNIVERSALSTRING: case V_ASN1_SEQUENCE: wolfSSL_ASN1_STRING_free(at->value.asn1_string); break; default: WOLFSSL_MSG("Unknown or unsupported ASN1_TYPE"); break; } XFREE(at, NULL, DYNAMIC_TYPE_OPENSSL); } } #endif /* OPENSSL_ALL || WOLFSSL_APACHE_HTTPD || WOLFSSL_HAPROXY || WOLFSSL_WPAS || OPENSSL_EXTRA */ #ifndef NO_WOLFSSL_STUB /*** TBD ***/ WOLFSSL_API WOLFSSL_EVP_PKEY *wolfSSL_get_privatekey(const WOLFSSL *ssl) { (void)ssl; WOLFSSL_STUB("SSL_get_privatekey"); return NULL; } #endif /** * Get a textual representation of given WOLFSSL_ASN1_OBJECT then write it to * buf at most buf_len bytes. * * params * - buf: buffer where the textual representation is to be written to * - buf_len: buffer size in bytes * - a: WOLFSSL_ASN1_OBJECT * * return the string length written on success, WOLFSSL_FAILURE on failure. */ WOLFSSL_API int wolfSSL_i2t_ASN1_OBJECT(char *buf, int buf_len, WOLFSSL_ASN1_OBJECT *a) { WOLFSSL_ENTER("wolfSSL_i2t_ASN1_OBJECT"); return wolfSSL_OBJ_obj2txt(buf, buf_len, a, 0); } WOLFSSL_ASN1_OBJECT *wolfSSL_d2i_ASN1_OBJECT(WOLFSSL_ASN1_OBJECT **a, const unsigned char **der, long length) { const unsigned char *d; long len; int tag, cls; WOLFSSL_ASN1_OBJECT* ret = NULL; WOLFSSL_ENTER("wolfSSL_d2i_ASN1_OBJECT"); if (!der || !*der || length <= 0) { WOLFSSL_MSG("Bad parameter"); return NULL; } d = *der; if (wolfSSL_ASN1_get_object(&d, &len, &tag, &cls, length) & 0x80) { WOLFSSL_MSG("wolfSSL_ASN1_get_object error"); return NULL; } /* d now points to value */ if (tag != ASN_OBJECT_ID) { WOLFSSL_MSG("Not an ASN object"); return NULL; } ret = wolfSSL_c2i_ASN1_OBJECT(a, &d, len); if (ret) *der = d; return ret; } /** * Parse an ASN1 encoded input and output information about the parsed object * @param in ASN1 encoded data. *in is moved to the value of the ASN1 object * @param len Length of parsed ASN1 object * @param tag Tag value of parsed ASN1 object * @param cls Class of parsed ASN1 object * @param inLen Length of *in buffer * @return int Depends on which bits are set in the returned int: * 0x80 an error occurred during parsing * 0x20 parsed object is constructed * 0x01 the parsed object length is infinite */ int wolfSSL_ASN1_get_object(const unsigned char **in, long *len, int *tag, int *cls, long inLen) { word32 inOutIdx = 0; int l; byte t; int ret = 0x80; WOLFSSL_ENTER("wolfSSL_ASN1_get_object"); if (!in || !*in || !len || !tag || !cls || inLen == 0) { WOLFSSL_MSG("Bad parameter"); return ret; } if (GetASNTag(*in, &inOutIdx, &t, (word32)inLen) != 0) { WOLFSSL_MSG("GetASNTag error"); return ret; } if (GetLength(*in, &inOutIdx, &l, (word32)inLen) < 0) { WOLFSSL_MSG("GetLength error"); return ret; } *tag = t & 0x1F; /* Tag number is 5 lsb */ *cls = t & 0xC0; /* Class is 2 msb */ *len = l; ret = t & ASN_CONSTRUCTED; if (l > (int)(inLen - inOutIdx)) { /* Still return other values but indicate error in msb */ ret |= 0x80; } *in += inOutIdx; return ret; } WOLFSSL_ASN1_OBJECT *wolfSSL_c2i_ASN1_OBJECT(WOLFSSL_ASN1_OBJECT **a, const unsigned char **pp, long len) { WOLFSSL_ASN1_OBJECT* ret = NULL; WOLFSSL_ENTER("wolfSSL_c2i_ASN1_OBJECT"); if (!pp || !*pp || len <= 0) { WOLFSSL_MSG("Bad parameter"); return NULL; } if (!(ret = wolfSSL_ASN1_OBJECT_new())) { WOLFSSL_MSG("wolfSSL_ASN1_OBJECT_new error"); return NULL; } ret->obj = (const unsigned char*)XMALLOC(len, NULL, DYNAMIC_TYPE_ASN1); if (!ret->obj) { WOLFSSL_MSG("error allocating asn data memory"); wolfSSL_ASN1_OBJECT_free(ret); return NULL; } XMEMCPY((byte*)ret->obj, *pp, len); ret->objSz = (unsigned int)len; ret->dynamic |= WOLFSSL_ASN1_DYNAMIC_DATA; *pp += len; if (a) *a = ret; return ret; } #ifndef NO_BIO /* Return number of bytes written to BIO on success. 0 on failure. */ WOLFSSL_API int wolfSSL_i2a_ASN1_OBJECT(WOLFSSL_BIO *bp, WOLFSSL_ASN1_OBJECT *a) { int length = 0; word32 idx = 0; const char null_str[] = "NULL"; WOLFSSL_ENTER("wolfSSL_i2a_ASN1_OBJECT"); if (bp == NULL) return WOLFSSL_FAILURE; if (a == NULL) { /* Write "NULL" */ if (wolfSSL_BIO_write(bp, null_str, (int)XSTRLEN(null_str)) == (int)XSTRLEN(null_str)) { return (int)XSTRLEN(null_str); } else { return WOLFSSL_FAILURE; } } if ((a->obj == NULL) || (a->obj[idx++] != ASN_OBJECT_ID)) { WOLFSSL_MSG("Bad ASN1 Object"); return WOLFSSL_FAILURE; } if (GetLength((const byte*)a->obj, &idx, &length, a->objSz) < 0 || length < 0) { return WOLFSSL_FAILURE; } if (wolfSSL_BIO_write(bp, a->obj + idx, length) == (int)length) { return length; } return WOLFSSL_FAILURE; } #endif /* !NO_BIO */ /* Returns object data for an ASN1_OBJECT */ /* If pp is NULL then only the size is returned */ /* If pp has pointer to pointer then its used directly */ /* If pp has pointer to pointer that is NULL then new variable is allocated */ /* Failure returns WOLFSSL_FAILURE (0) */ int wolfSSL_i2d_ASN1_OBJECT(WOLFSSL_ASN1_OBJECT *a, unsigned char **pp) { byte *p; WOLFSSL_ENTER("wolfSSL_i2d_ASN1_OBJECT"); if (!a || !a->obj) { WOLFSSL_MSG("Bad parameters"); return WOLFSSL_FAILURE; } if (!pp) return a->objSz; if (*pp) p = *pp; else { p = (byte*)XMALLOC(a->objSz, NULL, DYNAMIC_TYPE_OPENSSL); if (!p) { WOLFSSL_MSG("Bad malloc"); return WOLFSSL_FAILURE; } } XMEMCPY(p, a->obj, a->objSz); *pp = p + a->objSz; return a->objSz; } #ifndef NO_WOLFSSL_STUB /*** TBD ***/ WOLFSSL_API void SSL_CTX_set_tmp_dh_callback(WOLFSSL_CTX *ctx, WOLFSSL_DH *(*dh) (WOLFSSL *ssl, int is_export, int keylength)) { (void)ctx; (void)dh; WOLFSSL_STUB("SSL_CTX_set_tmp_dh_callback"); } #endif #ifndef NO_WOLFSSL_STUB /*** TBD ***/ WOLFSSL_API WOLF_STACK_OF(SSL_COMP) *SSL_COMP_get_compression_methods(void) { WOLFSSL_STUB("SSL_COMP_get_compression_methods"); return NULL; } #endif int wolfSSL_sk_SSL_CIPHER_num(const WOLF_STACK_OF(WOLFSSL_CIPHER)* p) { WOLFSSL_ENTER("wolfSSL_sk_SSL_CIPHER_num"); if (p == NULL) { return WOLFSSL_FATAL_ERROR; } return (int)p->num; } WOLFSSL_API WOLFSSL_CIPHER* wolfSSL_sk_SSL_CIPHER_value(WOLFSSL_STACK* sk, int i) { WOLFSSL_ENTER("wolfSSL_sk_SSL_CIPHER_value"); return (WOLFSSL_CIPHER*)wolfSSL_sk_value(sk, i); } #if !defined(NETOS) WOLFSSL_API void ERR_load_SSL_strings(void) { } #endif #ifdef HAVE_OCSP WOLFSSL_API long wolfSSL_get_tlsext_status_ocsp_resp(WOLFSSL *s, unsigned char **resp) { if (s == NULL || resp == NULL) return 0; *resp = s->ocspResp; return s->ocspRespSz; } WOLFSSL_API long wolfSSL_set_tlsext_status_ocsp_resp(WOLFSSL *s, unsigned char *resp, int len) { if (s == NULL) return WOLFSSL_FAILURE; s->ocspResp = resp; s->ocspRespSz = len; return WOLFSSL_SUCCESS; } #endif /* HAVE_OCSP */ #ifdef HAVE_MAX_FRAGMENT #ifndef NO_WOLFSSL_CLIENT /** * Set max fragment tls extension * @param c a pointer to WOLFSSL_CTX object * @param mode maximum fragment length mode * @return 1 on success, otherwise 0 or negative error code */ WOLFSSL_API int wolfSSL_CTX_set_tlsext_max_fragment_length(WOLFSSL_CTX *c, unsigned char mode) { if (c == NULL || (mode < WOLFSSL_MFL_2_9 || mode > WOLFSSL_MFL_2_12 )) return BAD_FUNC_ARG; return wolfSSL_CTX_UseMaxFragment(c, mode); } /** * Set max fragment tls extension * @param c a pointer to WOLFSSL object * @param mode maximum fragment length mode * @return 1 on success, otherwise 0 or negative error code */ WOLFSSL_API int wolfSSL_set_tlsext_max_fragment_length(WOLFSSL *s, unsigned char mode) { if (s == NULL || (mode < WOLFSSL_MFL_2_9 || mode > WOLFSSL_MFL_2_12 )) return BAD_FUNC_ARG; return wolfSSL_UseMaxFragment(s, mode); } #endif /* NO_WOLFSSL_CLIENT */ #endif /* HAVE_MAX_FRAGMENT */ #endif /* OPENSSL_EXTRA */ #ifdef WOLFSSL_HAVE_TLS_UNIQUE WOLFSSL_API size_t wolfSSL_get_finished(const WOLFSSL *ssl, void *buf, size_t count) { byte len = 0; WOLFSSL_ENTER("SSL_get_finished"); if (!ssl || !buf || count < TLS_FINISHED_SZ) { WOLFSSL_MSG("Bad parameter"); return WOLFSSL_FAILURE; } if (ssl->options.side == WOLFSSL_SERVER_END) { len = ssl->serverFinished_len; XMEMCPY(buf, ssl->serverFinished, len); } else { len = ssl->clientFinished_len; XMEMCPY(buf, ssl->clientFinished, len); } return len; } WOLFSSL_API size_t wolfSSL_get_peer_finished(const WOLFSSL *ssl, void *buf, size_t count) { byte len = 0; WOLFSSL_ENTER("SSL_get_peer_finished"); if (!ssl || !buf || count < TLS_FINISHED_SZ) { WOLFSSL_MSG("Bad parameter"); return WOLFSSL_FAILURE; } if (ssl->options.side == WOLFSSL_CLIENT_END) { len = ssl->serverFinished_len; XMEMCPY(buf, ssl->serverFinished, len); } else { len = ssl->clientFinished_len; XMEMCPY(buf, ssl->clientFinished, len); } return len; } #endif /* WOLFSSL_HAVE_TLS_UNIQUE */ #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) long wolfSSL_get_verify_result(const WOLFSSL *ssl) { if (ssl == NULL) { return WOLFSSL_FAILURE; } return ssl->peerVerifyRet; } #endif #ifdef OPENSSL_EXTRA #ifndef NO_WOLFSSL_STUB /* shows the number of accepts attempted by CTX in it's lifetime */ long wolfSSL_CTX_sess_accept(WOLFSSL_CTX* ctx) { WOLFSSL_STUB("wolfSSL_CTX_sess_accept"); (void)ctx; return 0; } #endif #ifndef NO_WOLFSSL_STUB /* shows the number of connects attempted CTX in it's lifetime */ long wolfSSL_CTX_sess_connect(WOLFSSL_CTX* ctx) { WOLFSSL_STUB("wolfSSL_CTX_sess_connect"); (void)ctx; return 0; } #endif #ifndef NO_WOLFSSL_STUB /* shows the number of accepts completed by CTX in it's lifetime */ long wolfSSL_CTX_sess_accept_good(WOLFSSL_CTX* ctx) { WOLFSSL_STUB("wolfSSL_CTX_sess_accept_good"); (void)ctx; return 0; } #endif #ifndef NO_WOLFSSL_STUB /* shows the number of connects completed by CTX in it's lifetime */ long wolfSSL_CTX_sess_connect_good(WOLFSSL_CTX* ctx) { WOLFSSL_STUB("wolfSSL_CTX_sess_connect_good"); (void)ctx; return 0; } #endif #ifndef NO_WOLFSSL_STUB /* shows the number of renegotiation accepts attempted by CTX */ long wolfSSL_CTX_sess_accept_renegotiate(WOLFSSL_CTX* ctx) { WOLFSSL_STUB("wolfSSL_CTX_sess_accept_renegotiate"); (void)ctx; return 0; } #endif #ifndef NO_WOLFSSL_STUB /* shows the number of renegotiation accepts attempted by CTX */ long wolfSSL_CTX_sess_connect_renegotiate(WOLFSSL_CTX* ctx) { WOLFSSL_STUB("wolfSSL_CTX_sess_connect_renegotiate"); (void)ctx; return 0; } #endif #ifndef NO_WOLFSSL_STUB long wolfSSL_CTX_sess_hits(WOLFSSL_CTX* ctx) { WOLFSSL_STUB("wolfSSL_CTX_sess_hits"); (void)ctx; return 0; } #endif #ifndef NO_WOLFSSL_STUB long wolfSSL_CTX_sess_cb_hits(WOLFSSL_CTX* ctx) { WOLFSSL_STUB("wolfSSL_CTX_sess_cb_hits"); (void)ctx; return 0; } #endif #ifndef NO_WOLFSSL_STUB long wolfSSL_CTX_sess_cache_full(WOLFSSL_CTX* ctx) { WOLFSSL_STUB("wolfSSL_CTX_sess_cache_full"); (void)ctx; return 0; } #endif #ifndef NO_WOLFSSL_STUB long wolfSSL_CTX_sess_misses(WOLFSSL_CTX* ctx) { WOLFSSL_STUB("wolfSSL_CTX_sess_misses"); (void)ctx; return 0; } #endif #ifndef NO_WOLFSSL_STUB long wolfSSL_CTX_sess_timeouts(WOLFSSL_CTX* ctx) { WOLFSSL_STUB("wolfSSL_CTX_sess_timeouts"); (void)ctx; return 0; } #endif /* Return the total number of sessions */ long wolfSSL_CTX_sess_number(WOLFSSL_CTX* ctx) { word32 total = 0; WOLFSSL_ENTER("wolfSSL_CTX_sess_number"); (void)ctx; #if defined(WOLFSSL_SESSION_STATS) && !defined(NO_SESSION_CACHE) if (wolfSSL_get_session_stats(NULL, &total, NULL, NULL) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("Error getting session stats"); } #else WOLFSSL_MSG("Please use macro WOLFSSL_SESSION_STATS for session stats"); #endif return (long)total; } #ifndef NO_CERTS long wolfSSL_CTX_add_extra_chain_cert(WOLFSSL_CTX* ctx, WOLFSSL_X509* x509) { byte* chain = NULL; long chainSz = 0; int derSz; const byte* der; int ret; int idx = 0; DerBuffer *derBuffer = NULL; WOLFSSL_ENTER("wolfSSL_CTX_add_extra_chain_cert"); if (ctx == NULL || x509 == NULL) { WOLFSSL_MSG("Bad Argument"); return WOLFSSL_FAILURE; } der = wolfSSL_X509_get_der(x509, &derSz); if (der == NULL || derSz <= 0) { WOLFSSL_MSG("Error getting X509 DER"); return WOLFSSL_FAILURE; } if (ctx->certificate == NULL) { WOLFSSL_ENTER("wolfSSL_use_certificate_chain_buffer_format"); /* Process buffer makes first certificate the leaf. */ ret = ProcessBuffer(ctx, der, derSz, WOLFSSL_FILETYPE_ASN1, CERT_TYPE, NULL, NULL, 1, GET_VERIFY_SETTING_CTX(ctx)); if (ret != WOLFSSL_SUCCESS) { WOLFSSL_LEAVE("wolfSSL_CTX_add_extra_chain_cert", ret); return WOLFSSL_FAILURE; } } else { /* TODO: Do this elsewhere. */ ret = AllocDer(&derBuffer, derSz, CERT_TYPE, ctx->heap); if (ret != 0) { WOLFSSL_MSG("Memory Error"); return WOLFSSL_FAILURE; } XMEMCPY(derBuffer->buffer, der, derSz); ret = AddCA(ctx->cm, &derBuffer, WOLFSSL_USER_CA, GET_VERIFY_SETTING_CTX(ctx)); if (ret != WOLFSSL_SUCCESS) { WOLFSSL_LEAVE("wolfSSL_CTX_add_extra_chain_cert", ret); return WOLFSSL_FAILURE; } /* adding cert to existing chain */ if (ctx->certChain != NULL && ctx->certChain->length > 0) { chainSz += ctx->certChain->length; } chainSz += OPAQUE24_LEN + derSz; chain = (byte*)XMALLOC(chainSz, ctx->heap, DYNAMIC_TYPE_DER); if (chain == NULL) { WOLFSSL_MSG("Memory Error"); return WOLFSSL_FAILURE; } if (ctx->certChain != NULL && ctx->certChain->length > 0) { XMEMCPY(chain, ctx->certChain->buffer, ctx->certChain->length); idx = ctx->certChain->length; } c32to24(derSz, chain + idx); idx += OPAQUE24_LEN; XMEMCPY(chain + idx, der, derSz); idx += derSz; #ifdef WOLFSSL_TLS13 ctx->certChainCnt++; #endif FreeDer(&ctx->certChain); ret = AllocDer(&ctx->certChain, idx, CERT_TYPE, ctx->heap); if (ret == 0) { XMEMCPY(ctx->certChain->buffer, chain, idx); } } /* on success WOLFSSL_X509 memory is responsibility of ctx */ wolfSSL_X509_free(x509); if (chain != NULL) XFREE(chain, ctx->heap, DYNAMIC_TYPE_DER); return WOLFSSL_SUCCESS; } long wolfSSL_CTX_set_tlsext_status_arg(WOLFSSL_CTX* ctx, void* arg) { if (ctx == NULL || ctx->cm == NULL) { return WOLFSSL_FAILURE; } ctx->cm->ocspIOCtx = arg; return WOLFSSL_SUCCESS; } #endif /* NO_CERTS */ /* Get the session cache mode for CTX * * ctx WOLFSSL_CTX struct to get cache mode from * * Returns a bit mask that has the session cache mode */ WOLFSSL_API long wolfSSL_CTX_get_session_cache_mode(WOLFSSL_CTX* ctx) { long m = 0; WOLFSSL_ENTER("SSL_CTX_set_session_cache_mode"); if (ctx == NULL) { return m; } if (ctx->sessionCacheOff != 1) { m |= SSL_SESS_CACHE_SERVER; } if (ctx->sessionCacheFlushOff == 1) { m |= SSL_SESS_CACHE_NO_AUTO_CLEAR; } #ifdef HAVE_EXT_CACHE if (ctx->internalCacheOff == 1) { m |= SSL_SESS_CACHE_NO_INTERNAL_STORE; } if (ctx->internalCacheLookupOff == 1) { m |= SSL_SESS_CACHE_NO_INTERNAL_LOOKUP; } #endif return m; } int wolfSSL_get_read_ahead(const WOLFSSL* ssl) { if (ssl == NULL) { return WOLFSSL_FAILURE; } return ssl->readAhead; } int wolfSSL_set_read_ahead(WOLFSSL* ssl, int v) { if (ssl == NULL) { return WOLFSSL_FAILURE; } ssl->readAhead = (byte)v; return WOLFSSL_SUCCESS; } int wolfSSL_CTX_get_read_ahead(WOLFSSL_CTX* ctx) { if (ctx == NULL) { return WOLFSSL_FAILURE; } return ctx->readAhead; } int wolfSSL_CTX_set_read_ahead(WOLFSSL_CTX* ctx, int v) { if (ctx == NULL) { return WOLFSSL_FAILURE; } ctx->readAhead = (byte)v; return WOLFSSL_SUCCESS; } long wolfSSL_CTX_set_tlsext_opaque_prf_input_callback_arg(WOLFSSL_CTX* ctx, void* arg) { if (ctx == NULL) { return WOLFSSL_FAILURE; } ctx->userPRFArg = arg; return WOLFSSL_SUCCESS; } #ifndef NO_DES3 /* 0 on success */ int wolfSSL_DES_set_key(WOLFSSL_const_DES_cblock* myDes, WOLFSSL_DES_key_schedule* key) { #ifdef WOLFSSL_CHECK_DESKEY return wolfSSL_DES_set_key_checked(myDes, key); #else wolfSSL_DES_set_key_unchecked(myDes, key); return 0; #endif } /* return true in fail case (1) */ static int DES_check(word32 mask, word32 mask2, unsigned char* key) { word32 value[2]; /* sanity check on length made in wolfSSL_DES_set_key_checked */ value[0] = mask; value[1] = mask2; return (XMEMCMP(value, key, sizeof(value)) == 0)? 1: 0; } /* check that the key is odd parity and is not a weak key * returns -1 if parity is wrong, -2 if weak/null key and 0 on success */ int wolfSSL_DES_set_key_checked(WOLFSSL_const_DES_cblock* myDes, WOLFSSL_DES_key_schedule* key) { if (myDes == NULL || key == NULL) { WOLFSSL_MSG("Bad argument passed to wolfSSL_DES_set_key_checked"); return -2; } else { word32 sz = sizeof(WOLFSSL_DES_key_schedule); /* sanity check before call to DES_check */ if (sz != (sizeof(word32) * 2)) { WOLFSSL_MSG("Unexpected WOLFSSL_DES_key_schedule size"); return -2; } /* check odd parity */ if (wolfSSL_DES_check_key_parity(myDes) != 1) { WOLFSSL_MSG("Odd parity test fail"); return -1; } if (wolfSSL_DES_is_weak_key(myDes) == 1) { WOLFSSL_MSG("Weak key found"); return -2; } /* passed tests, now copy over key */ XMEMCPY(key, myDes, sizeof(WOLFSSL_const_DES_cblock)); return 0; } } /* check is not weak. Weak key list from Nist "Recommendation for the Triple * Data Encryption Algorithm (TDEA) Block Cipher" * * returns 1 if is weak 0 if not */ int wolfSSL_DES_is_weak_key(WOLFSSL_const_DES_cblock* key) { word32 mask, mask2; WOLFSSL_ENTER("wolfSSL_DES_is_weak_key"); if (key == NULL) { WOLFSSL_MSG("NULL key passed in"); return 1; } mask = 0x01010101; mask2 = 0x01010101; if (DES_check(mask, mask2, *key)) { WOLFSSL_MSG("Weak key found"); return 1; } mask = 0xFEFEFEFE; mask2 = 0xFEFEFEFE; if (DES_check(mask, mask2, *key)) { WOLFSSL_MSG("Weak key found"); return 1; } mask = 0xE0E0E0E0; mask2 = 0xF1F1F1F1; if (DES_check(mask, mask2, *key)) { WOLFSSL_MSG("Weak key found"); return 1; } mask = 0x1F1F1F1F; mask2 = 0x0E0E0E0E; if (DES_check(mask, mask2, *key)) { WOLFSSL_MSG("Weak key found"); return 1; } /* semi-weak *key check (list from same Nist paper) */ mask = 0x011F011F; mask2 = 0x010E010E; if (DES_check(mask, mask2, *key) || DES_check(ByteReverseWord32(mask), ByteReverseWord32(mask2), *key)) { WOLFSSL_MSG("Weak key found"); return 1; } mask = 0x01E001E0; mask2 = 0x01F101F1; if (DES_check(mask, mask2, *key) || DES_check(ByteReverseWord32(mask), ByteReverseWord32(mask2), *key)) { WOLFSSL_MSG("Weak key found"); return 1; } mask = 0x01FE01FE; mask2 = 0x01FE01FE; if (DES_check(mask, mask2, *key) || DES_check(ByteReverseWord32(mask), ByteReverseWord32(mask2), *key)) { WOLFSSL_MSG("Weak key found"); return 1; } mask = 0x1FE01FE0; mask2 = 0x0EF10EF1; if (DES_check(mask, mask2, *key) || DES_check(ByteReverseWord32(mask), ByteReverseWord32(mask2), *key)) { WOLFSSL_MSG("Weak key found"); return 1; } mask = 0x1FFE1FFE; mask2 = 0x0EFE0EFE; if (DES_check(mask, mask2, *key) || DES_check(ByteReverseWord32(mask), ByteReverseWord32(mask2), *key)) { WOLFSSL_MSG("Weak key found"); return 1; } return 0; } void wolfSSL_DES_set_key_unchecked(WOLFSSL_const_DES_cblock* myDes, WOLFSSL_DES_key_schedule* key) { if (myDes != NULL && key != NULL) { XMEMCPY(key, myDes, sizeof(WOLFSSL_const_DES_cblock)); } } /* Sets the parity of the DES key for use */ void wolfSSL_DES_set_odd_parity(WOLFSSL_DES_cblock* myDes) { word32 i; word32 sz = sizeof(WOLFSSL_DES_cblock); WOLFSSL_ENTER("wolfSSL_DES_set_odd_parity"); for (i = 0; i < sz; i++) { unsigned char c = (*myDes)[i]; if (( ((c >> 1) & 0x01) ^ ((c >> 2) & 0x01) ^ ((c >> 3) & 0x01) ^ ((c >> 4) & 0x01) ^ ((c >> 5) & 0x01) ^ ((c >> 6) & 0x01) ^ ((c >> 7) & 0x01)) == (c & 0x01)) { WOLFSSL_MSG("Flipping parity bit"); (*myDes)[i] = c ^ 0x01; } } } int wolfSSL_DES_check_key_parity(WOLFSSL_DES_cblock *myDes) { word32 i; word32 sz = sizeof(WOLFSSL_DES_cblock); WOLFSSL_ENTER("wolfSSL_DES_check_key_parity"); for (i = 0; i < sz; i++) { unsigned char c = (*myDes)[i]; if (( ((c >> 1) & 0x01) ^ ((c >> 2) & 0x01) ^ ((c >> 3) & 0x01) ^ ((c >> 4) & 0x01) ^ ((c >> 5) & 0x01) ^ ((c >> 6) & 0x01) ^ ((c >> 7) & 0x01)) == (c & 0x01)) { return 0; } } return 1; } #ifdef WOLFSSL_DES_ECB /* Encrypt or decrypt input message desa with key and get output in desb. * if enc is DES_ENCRYPT,input message is encrypted or * if enc is DES_DECRYPT,input message is decrypted. * */ void wolfSSL_DES_ecb_encrypt(WOLFSSL_DES_cblock* desa, WOLFSSL_DES_cblock* desb, WOLFSSL_DES_key_schedule* key, int enc) { Des myDes; WOLFSSL_ENTER("wolfSSL_DES_ecb_encrypt"); if (desa == NULL || key == NULL || desb == NULL || (enc != DES_ENCRYPT && enc != DES_DECRYPT)) { WOLFSSL_MSG("Bad argument passed to wolfSSL_DES_ecb_encrypt"); } else { if (wc_Des_SetKey(&myDes, (const byte*) key, (const byte*) NULL, !enc) != 0) { WOLFSSL_MSG("wc_Des_SetKey return error."); return; } if (enc == DES_ENCRYPT){ if (wc_Des_EcbEncrypt(&myDes, (byte*) desb, (const byte*) desa, sizeof(WOLFSSL_DES_cblock)) != 0){ WOLFSSL_MSG("wc_Des_EcbEncrypt return error."); } } else { if (wc_Des_EcbDecrypt(&myDes, (byte*) desb, (const byte*) desa, sizeof(WOLFSSL_DES_cblock)) != 0){ WOLFSSL_MSG("wc_Des_EcbDecrpyt return error."); } } } } #endif #endif /* NO_DES3 */ #ifndef NO_RC4 /* Set the key state for Arc4 structure. * * key Arc4 structure to use * len length of data buffer * data initial state to set Arc4 structure */ void wolfSSL_RC4_set_key(WOLFSSL_RC4_KEY* key, int len, const unsigned char* data) { typedef char rc4_test[sizeof(WOLFSSL_RC4_KEY) >= sizeof(Arc4) ? 1 : -1]; (void)sizeof(rc4_test); WOLFSSL_ENTER("wolfSSL_RC4_set_key"); if (key == NULL || len < 0) { WOLFSSL_MSG("bad argument passed in"); return; } XMEMSET(key, 0, sizeof(WOLFSSL_RC4_KEY)); wc_Arc4SetKey((Arc4*)key, data, (word32)len); } /* Encrypt/decrypt with Arc4 structure. * * len length of buffer to encrypt/decrypt (in/out) * in buffer to encrypt/decrypt * out results of encryption/decryption */ void wolfSSL_RC4(WOLFSSL_RC4_KEY* key, size_t len, const unsigned char* in, unsigned char* out) { WOLFSSL_ENTER("wolfSSL_RC4"); if (key == NULL || in == NULL || out == NULL) { WOLFSSL_MSG("Bad argument passed in"); return; } wc_Arc4Process((Arc4*)key, out, in, (word32)len); } #endif /* NO_RC4 */ #ifndef NO_AES #ifdef WOLFSSL_AES_DIRECT /* AES encrypt direct, it is expected to be blocks of AES_BLOCK_SIZE for input. * * input Data to encrypt * output Encrypted data after done * key AES key to use for encryption */ void wolfSSL_AES_encrypt(const unsigned char* input, unsigned char* output, AES_KEY *key) { WOLFSSL_ENTER("wolfSSL_AES_encrypt"); if (input == NULL || output == NULL || key == NULL) { WOLFSSL_MSG("Null argument passed in"); return; } #if !defined(HAVE_SELFTEST) && \ (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) if (wc_AesEncryptDirect((Aes*)key, output, input) != 0) { WOLFSSL_MSG("wc_AesEncryptDirect failed"); return; } #else wc_AesEncryptDirect((Aes*)key, output, input); #endif } /* AES decrypt direct, it is expected to be blocks of AES_BLOCK_SIZE for input. * * input Data to decrypt * output Decrypted data after done * key AES key to use for encryption */ void wolfSSL_AES_decrypt(const unsigned char* input, unsigned char* output, AES_KEY *key) { WOLFSSL_ENTER("wolfSSL_AES_decrypt"); if (input == NULL || output == NULL || key == NULL) { WOLFSSL_MSG("Null argument passed in"); return; } #if !defined(HAVE_SELFTEST) && \ (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) if (wc_AesDecryptDirect((Aes*)key, output, input) != 0) { WOLFSSL_MSG("wc_AesDecryptDirect failed"); return; } #else wc_AesDecryptDirect((Aes*)key, output, input); #endif } #endif /* WOLFSSL_AES_DIRECT */ /* Setup of an AES key to use for encryption. * * key key in bytes to use for encryption * bits size of key in bits * aes AES structure to initialize */ int wolfSSL_AES_set_encrypt_key(const unsigned char *key, const int bits, AES_KEY *aes) { typedef char aes_test[sizeof(AES_KEY) >= sizeof(Aes) ? 1 : -1]; (void)sizeof(aes_test); WOLFSSL_ENTER("wolfSSL_AES_set_encrypt_key"); if (key == NULL || aes == NULL) { WOLFSSL_MSG("Null argument passed in"); return -1; } XMEMSET(aes, 0, sizeof(AES_KEY)); if (wc_AesSetKey((Aes*)aes, key, ((bits)/8), NULL, AES_ENCRYPT) != 0) { WOLFSSL_MSG("Error in setting AES key"); return -1; } return 0; } /* Setup of an AES key to use for decryption. * * key key in bytes to use for decryption * bits size of key in bits * aes AES structure to initialize */ int wolfSSL_AES_set_decrypt_key(const unsigned char *key, const int bits, AES_KEY *aes) { typedef char aes_test[sizeof(AES_KEY) >= sizeof(Aes) ? 1 : -1]; (void)sizeof(aes_test); WOLFSSL_ENTER("wolfSSL_AES_set_decrypt_key"); if (key == NULL || aes == NULL) { WOLFSSL_MSG("Null argument passed in"); return -1; } XMEMSET(aes, 0, sizeof(AES_KEY)); if (wc_AesSetKey((Aes*)aes, key, ((bits)/8), NULL, AES_DECRYPT) != 0) { WOLFSSL_MSG("Error in setting AES key"); return -1; } return 0; } #ifdef HAVE_AES_ECB /* Encrypt/decrypt a 16 byte block of data using the key passed in. * * in buffer to encrypt/decrypt * out buffer to hold result of encryption/decryption * key AES structure to use with encryption/decryption * enc AES_ENCRPT for encryption and AES_DECRYPT for decryption */ void wolfSSL_AES_ecb_encrypt(const unsigned char *in, unsigned char* out, AES_KEY *key, const int enc) { Aes* aes; WOLFSSL_ENTER("wolfSSL_AES_ecb_encrypt"); if (key == NULL || in == NULL || out == NULL) { WOLFSSL_MSG("Error, Null argument passed in"); return; } aes = (Aes*)key; if (enc == AES_ENCRYPT) { if (wc_AesEcbEncrypt(aes, out, in, AES_BLOCK_SIZE) != 0) { WOLFSSL_MSG("Error with AES CBC encrypt"); } } else { #ifdef HAVE_AES_DECRYPT if (wc_AesEcbDecrypt(aes, out, in, AES_BLOCK_SIZE) != 0) { WOLFSSL_MSG("Error with AES CBC decrypt"); } #else WOLFSSL_MSG("AES decryption not compiled in"); #endif } } #endif /* HAVE_AES_ECB */ #ifdef HAVE_AES_CBC /* Encrypt data using key and iv passed in. iv gets updated to most recent iv * state after encryption/decryption. * * in buffer to encrypt/decrypt * out buffer to hold result of encryption/decryption * len length of input buffer * key AES structure to use with encryption/decryption * iv iv to use with operation * enc 1 for encryption and 0 for decryption */ void wolfSSL_AES_cbc_encrypt(const unsigned char *in, unsigned char* out, size_t len, AES_KEY *key, unsigned char* iv, const int enc) { Aes* aes; WOLFSSL_ENTER("wolfSSL_AES_cbc_encrypt"); if (key == NULL || in == NULL || out == NULL || iv == NULL || len == 0) { WOLFSSL_MSG("Error, Null argument passed in"); return; } aes = (Aes*)key; if (wc_AesSetIV(aes, (const byte*)iv) != 0) { WOLFSSL_MSG("Error with setting iv"); return; } if (enc == AES_ENCRYPT) { if (wc_AesCbcEncrypt(aes, out, in, (word32)len) != 0) { WOLFSSL_MSG("Error with AES CBC encrypt"); return; } } else { if (wc_AesCbcDecrypt(aes, out, in, (word32)len) != 0) { WOLFSSL_MSG("Error with AES CBC decrypt"); return; } } /* to be compatible copy iv to iv buffer after completing operation */ XMEMCPY(iv, (byte*)(aes->reg), AES_BLOCK_SIZE); } #endif /* HAVE_AES_CBC */ /* Encrypt data using CFB mode with key and iv passed in. iv gets updated to * most recent iv state after encryption/decryption. * * in buffer to encrypt/decrypt * out buffer to hold result of encryption/decryption * len length of input buffer * key AES structure to use with encryption/decryption * iv iv to use with operation * num contains the amount of block used * enc AES_ENCRYPT for encryption and AES_DECRYPT for decryption */ void wolfSSL_AES_cfb128_encrypt(const unsigned char *in, unsigned char* out, size_t len, AES_KEY *key, unsigned char* iv, int* num, const int enc) { #ifndef WOLFSSL_AES_CFB WOLFSSL_MSG("CFB mode not enabled please use macro WOLFSSL_AES_CFB"); (void)in; (void)out; (void)len; (void)key; (void)iv; (void)num; (void)enc; return; #else Aes* aes; WOLFSSL_ENTER("wolfSSL_AES_cbc_encrypt"); if (key == NULL || in == NULL || out == NULL || iv == NULL) { WOLFSSL_MSG("Error, Null argument passed in"); return; } aes = (Aes*)key; /* * We copy the IV directly into reg here because using wc_AesSetIV will * clear the leftover bytes field "left", and this function relies on the * leftover bytes being preserved between calls. */ XMEMCPY(aes->reg, iv, AES_BLOCK_SIZE); if (enc == AES_ENCRYPT) { if (wc_AesCfbEncrypt(aes, out, in, (word32)len) != 0) { WOLFSSL_MSG("Error with AES CBC encrypt"); return; } } else { if (wc_AesCfbDecrypt(aes, out, in, (word32)len) != 0) { WOLFSSL_MSG("Error with AES CBC decrypt"); return; } } /* to be compatible copy iv to iv buffer after completing operation */ XMEMCPY(iv, (byte*)(aes->reg), AES_BLOCK_SIZE); /* store number of left over bytes to num */ *num = (aes->left)? AES_BLOCK_SIZE - aes->left : 0; #endif /* WOLFSSL_AES_CFB */ } /* wc_AesKey*Wrap_ex API not available in FIPS and SELFTEST */ #if defined(HAVE_AES_KEYWRAP) && !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) int wolfSSL_AES_wrap_key(AES_KEY *key, const unsigned char *iv, unsigned char *out, const unsigned char *in, unsigned int inlen) { int ret; WOLFSSL_ENTER("wolfSSL_AES_wrap_key"); if (out == NULL || in == NULL) { WOLFSSL_MSG("Error, Null argument passed in"); return WOLFSSL_FAILURE; } ret = wc_AesKeyWrap_ex((Aes*)key, in, inlen, out, inlen + KEYWRAP_BLOCK_SIZE, iv); return ret < 0 ? WOLFSSL_FAILURE : ret; } int wolfSSL_AES_unwrap_key(AES_KEY *key, const unsigned char *iv, unsigned char *out, const unsigned char *in, unsigned int inlen) { int ret; WOLFSSL_ENTER("wolfSSL_AES_wrap_key"); if (out == NULL || in == NULL) { WOLFSSL_MSG("Error, Null argument passed in"); return WOLFSSL_FAILURE; } ret = wc_AesKeyUnWrap_ex((Aes*)key, in, inlen, out, inlen + KEYWRAP_BLOCK_SIZE, iv); return ret < 0 ? WOLFSSL_FAILURE : ret; } #endif /* HAVE_AES_KEYWRAP && !HAVE_FIPS && !HAVE_SELFTEST */ #ifdef HAVE_CTS /* * Ciphertext stealing interface compatible with RFC2040 and RFC3962. */ size_t wolfSSL_CRYPTO_cts128_encrypt(const unsigned char *in, unsigned char *out, size_t len, const void *key, unsigned char *iv, WOLFSSL_CBC128_CB cbc) { byte lastBlk[WOLFSSL_CTS128_BLOCK_SZ]; int lastBlkLen = len % WOLFSSL_CTS128_BLOCK_SZ; WOLFSSL_ENTER("wolfSSL_CRYPTO_cts128_encrypt"); if (in == NULL || out == NULL || len < WOLFSSL_CTS128_BLOCK_SZ || cbc == NULL) { WOLFSSL_MSG("Bad parameter"); return WOLFSSL_FAILURE; } if (lastBlkLen == 0) lastBlkLen = WOLFSSL_CTS128_BLOCK_SZ; /* Encrypt data up to last block */ (*cbc)(in, out, len - lastBlkLen, key, iv, AES_ENCRYPT); /* Move to last block */ in += len - lastBlkLen; out += len - lastBlkLen; /* RFC2040: Pad Pn with zeros at the end to create P of length BB. */ XMEMCPY(lastBlk, in, lastBlkLen); XMEMSET(lastBlk + lastBlkLen, 0, WOLFSSL_CTS128_BLOCK_SZ - lastBlkLen); /* RFC2040: Select the first Ln bytes of En-1 to create Cn */ XMEMCPY(out, out - WOLFSSL_CTS128_BLOCK_SZ, lastBlkLen); (*cbc)(lastBlk, out - WOLFSSL_CTS128_BLOCK_SZ, WOLFSSL_CTS128_BLOCK_SZ, key, iv, AES_ENCRYPT); return len; } size_t wolfSSL_CRYPTO_cts128_decrypt(const unsigned char *in, unsigned char *out, size_t len, const void *key, unsigned char *iv, WOLFSSL_CBC128_CB cbc) { byte lastBlk[WOLFSSL_CTS128_BLOCK_SZ]; byte prevBlk[WOLFSSL_CTS128_BLOCK_SZ]; int lastBlkLen = len % WOLFSSL_CTS128_BLOCK_SZ; WOLFSSL_ENTER("wolfSSL_CRYPTO_cts128_decrypt"); if (in == NULL || out == NULL || len <= WOLFSSL_CTS128_BLOCK_SZ || cbc == NULL) { WOLFSSL_MSG("Bad parameter"); return WOLFSSL_FAILURE; } if (lastBlkLen == 0) lastBlkLen = WOLFSSL_CTS128_BLOCK_SZ; /* Decrypt up to last two blocks */ (*cbc)(in, out, len - lastBlkLen - WOLFSSL_CTS128_BLOCK_SZ, key, iv, AES_DECRYPTION); /* Move to last two blocks */ in += len - lastBlkLen - WOLFSSL_CTS128_BLOCK_SZ; out += len - lastBlkLen - WOLFSSL_CTS128_BLOCK_SZ; /* RFC2040: Decrypt Cn-1 to create Dn. * Use 0 buffer as IV to do straight decryption. * This places the Cn-1 block at lastBlk */ XMEMSET(lastBlk, 0, WOLFSSL_CTS128_BLOCK_SZ); (*cbc)(in, prevBlk, WOLFSSL_CTS128_BLOCK_SZ, key, lastBlk, AES_DECRYPT); /* RFC2040: Append the tail (BB minus Ln) bytes of Xn to Cn * to create En. */ XMEMCPY(prevBlk, in + WOLFSSL_CTS128_BLOCK_SZ, lastBlkLen); /* Cn and Cn-1 can now be decrypted */ (*cbc)(prevBlk, out, WOLFSSL_CTS128_BLOCK_SZ, key, iv, AES_DECRYPT); (*cbc)(lastBlk, lastBlk, WOLFSSL_CTS128_BLOCK_SZ, key, iv, AES_DECRYPT); XMEMCPY(out + WOLFSSL_CTS128_BLOCK_SZ, lastBlk, lastBlkLen); return len; } #endif /* HAVE_CTS */ #endif /* NO_AES */ #ifndef NO_ASN_TIME #ifndef NO_BIO int wolfSSL_ASN1_UTCTIME_print(WOLFSSL_BIO* bio, const WOLFSSL_ASN1_UTCTIME* a) { WOLFSSL_ENTER("ASN1_UTCTIME_print"); if (bio == NULL || a == NULL) { return WOLFSSL_FAILURE; } if (a->type != ASN_UTC_TIME) { WOLFSSL_MSG("Error, not UTC_TIME"); return WOLFSSL_FAILURE; } return wolfSSL_ASN1_TIME_print(bio, a); } #endif /* !NO_BIO */ /* Checks the ASN1 syntax of "a" * returns WOLFSSL_SUCCESS (1) if correct otherwise WOLFSSL_FAILURE (0) */ int wolfSSL_ASN1_TIME_check(const WOLFSSL_ASN1_TIME* a) { char buf[MAX_TIME_STRING_SZ]; WOLFSSL_ENTER("wolfSSL_ASN1_TIME_check"); /* if can parse the WOLFSSL_ASN1_TIME passed in then consider syntax good */ if (wolfSSL_ASN1_TIME_to_string((WOLFSSL_ASN1_TIME*)a, buf, MAX_TIME_STRING_SZ) == NULL) { return WOLFSSL_FAILURE; } return WOLFSSL_SUCCESS; } /* * Convert time to Unix time (GMT). */ static long long TimeToUnixTime(int sec, int min, int hour, int mday, int mon, int year) { /* Number of cumulative days from the previous months, starting from * beginning of January. */ static const int monthDaysCumulative [12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; int leapDays = year; if (mon <= 1) { --leapDays; } leapDays = leapDays / 4 - leapDays / 100 + leapDays / 400 - 1969 / 4 + 1969 / 100 - 1969 / 400; return ((((long long) (year - 1970) * 365 + leapDays + monthDaysCumulative[mon] + mday - 1) * 24 + hour) * 60 + min) * 60 + sec; } int wolfSSL_ASN1_TIME_diff(int *days, int *secs, const WOLFSSL_ASN1_TIME *from, const WOLFSSL_ASN1_TIME *to) { const int SECS_PER_DAY = 24 * 60 * 60; struct tm fromTm_s, *fromTmGmt = &fromTm_s; struct tm toTm_s, *toTmGmt = &toTm_s; time_t currTime; long long fromSecs; long long toSecs; double diffSecs; struct tm *tmpTs; #if defined(NEED_TMP_TIME) /* for use with gmtime_r */ struct tm tmpTimeStorage; tmpTs = &tmpTimeStorage; #else tmpTs = NULL; #endif (void)tmpTs; WOLFSSL_ENTER("wolfSSL_ASN1_TIME_diff"); if (days == NULL) { WOLFSSL_MSG("days is NULL"); return WOLFSSL_FAILURE; } if (secs == NULL) { WOLFSSL_MSG("secs is NULL"); return WOLFSSL_FAILURE; } if (from == NULL && to == NULL) { *days = 0; *secs = 0; return WOLFSSL_SUCCESS; } if (from == NULL) { currTime = wc_Time(0); fromTmGmt = XGMTIME(&currTime, tmpTs); if (fromTmGmt == NULL) { WOLFSSL_MSG("XGMTIME for from time failed."); return WOLFSSL_FAILURE; } } else if (wolfSSL_ASN1_TIME_to_tm(from, fromTmGmt) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("Failed to convert from time to struct tm."); return WOLFSSL_FAILURE; } /* We use TimeToUnixTime here instead of XMKTIME to avoid the Year 2038 * Problem on platforms where time_t is 32 bits. struct tm stores the year * as years since 1900, so we add 1900 to the year. */ fromSecs = TimeToUnixTime(fromTmGmt->tm_sec, fromTmGmt->tm_min, fromTmGmt->tm_hour, fromTmGmt->tm_mday, fromTmGmt->tm_mon, fromTmGmt->tm_year + 1900); if (to == NULL) { currTime = wc_Time(0); toTmGmt = XGMTIME(&currTime, tmpTs); if (toTmGmt == NULL) { WOLFSSL_MSG("XGMTIME for to time failed."); return WOLFSSL_FAILURE; } } else if (wolfSSL_ASN1_TIME_to_tm(to, toTmGmt) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("Failed to convert to time to struct tm."); return WOLFSSL_FAILURE; } toSecs = TimeToUnixTime(toTmGmt->tm_sec, toTmGmt->tm_min, toTmGmt->tm_hour, toTmGmt->tm_mday, toTmGmt->tm_mon, toTmGmt->tm_year + 1900); diffSecs = (double)(toSecs - fromSecs); *days = (int) (diffSecs / SECS_PER_DAY); *secs = (int) (diffSecs - (((double)*days) * SECS_PER_DAY)); return WOLFSSL_SUCCESS; } int wolfSSL_ASN1_TIME_compare(const WOLFSSL_ASN1_TIME *a, const WOLFSSL_ASN1_TIME *b) { int ret; int days; int secs; WOLFSSL_ENTER("wolfSSL_ASN1_TIME_compare"); if (wolfSSL_ASN1_TIME_diff(&days, &secs, a, b) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("Failed to get time difference."); ret = -2; } else { if (days == 0 && secs == 0) { /* a and b are the same time. */ ret = 0; } else if (days >= 0 && secs >= 0) { /* a is before b. */ ret = -1; } else if (days <= 0 && secs <= 0) { /* a is after b. */ ret = 1; } else { WOLFSSL_MSG("Incoherent time difference."); ret = -2; } } WOLFSSL_LEAVE("wolfSSL_ASN1_TIME_compare", ret); return ret; } #endif /* !NO_ASN_TIME */ #ifndef NO_WOLFSSL_STUB WOLFSSL_ASN1_TIME *wolfSSL_ASN1_TIME_set(WOLFSSL_ASN1_TIME *s, time_t t) { WOLFSSL_STUB("wolfSSL_ASN1_TIME_set"); (void)s; (void)t; return s; } #endif /* !NO_WOLFSSL_STUB */ int wolfSSL_ASN1_TIME_set_string(WOLFSSL_ASN1_TIME *s, const char *str) { int slen; WOLFSSL_ENTER("wolfSSL_ASN1_TIME_set_string"); if (!str) { WOLFSSL_MSG("Bad parameter"); return WOLFSSL_FAILURE; } slen = (int)XSTRLEN(str)+1; if (slen > CTC_DATE_SIZE) { WOLFSSL_MSG("Date string too long"); return WOLFSSL_FAILURE; } if (s) { XMEMCPY(s->data, str, slen); s->length = slen - 1; /* do not include null terminator in length */ s->type = slen == ASN_UTC_TIME_SIZE ? V_ASN1_UTCTIME : V_ASN1_GENERALIZEDTIME; } return WOLFSSL_SUCCESS; } #ifndef NO_BIO /* Return the month as a string. * * n The number of the month as a two characters (1 based). * returns the month as a string. */ static WC_INLINE const char* MonthStr(const char* n) { static const char monthStr[12][4] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; return monthStr[(n[0] - '0') * 10 + (n[1] - '0') - 1]; } int wolfSSL_ASN1_GENERALIZEDTIME_print(WOLFSSL_BIO* bio, const WOLFSSL_ASN1_GENERALIZEDTIME* asnTime) { const char* p; WOLFSSL_ENTER("wolfSSL_ASN1_GENERALIZEDTIME_print"); if (bio == NULL || asnTime == NULL) return BAD_FUNC_ARG; if (asnTime->type != ASN_GENERALIZED_TIME) { WOLFSSL_MSG("Error, not GENERALIZED_TIME"); return WOLFSSL_FAILURE; } p = (const char *)(asnTime->data); /* GetTimeString not always available. */ if (wolfSSL_BIO_write(bio, MonthStr(p + 4), 3) <= 0) return WOLFSSL_FAILURE; if (wolfSSL_BIO_write(bio, " ", 1) <= 0) return WOLFSSL_FAILURE; /* Day */ if (wolfSSL_BIO_write(bio, p + 6, 2) <= 0) return WOLFSSL_FAILURE; if (wolfSSL_BIO_write(bio, " ", 1) <= 0) return WOLFSSL_FAILURE; /* Hour */ if (wolfSSL_BIO_write(bio, p + 8, 2) <= 0) return WOLFSSL_FAILURE; if (wolfSSL_BIO_write(bio, ":", 1) <= 0) return WOLFSSL_FAILURE; /* Min */ if (wolfSSL_BIO_write(bio, p + 10, 2) <= 0) return WOLFSSL_FAILURE; if (wolfSSL_BIO_write(bio, ":", 1) <= 0) return WOLFSSL_FAILURE; /* Secs */ if (wolfSSL_BIO_write(bio, p + 12, 2) <= 0) return WOLFSSL_FAILURE; if (wolfSSL_BIO_write(bio, " ", 1) <= 0) return WOLFSSL_FAILURE; if (wolfSSL_BIO_write(bio, p, 4) <= 0) return WOLFSSL_FAILURE; return 0; } #endif /* !NO_BIO */ void wolfSSL_ASN1_GENERALIZEDTIME_free(WOLFSSL_ASN1_TIME* asn1Time) { WOLFSSL_ENTER("wolfSSL_ASN1_GENERALIZEDTIME_free"); if (asn1Time == NULL) return; XMEMSET(asn1Time->data, 0, sizeof(asn1Time->data)); } #endif /* OPENSSL_EXTRA */ #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) int wolfSSL_sk_num(const WOLFSSL_STACK* sk) { WOLFSSL_ENTER("wolfSSL_sk_num"); if (sk == NULL) return 0; return (int)sk->num; } void* wolfSSL_sk_value(const WOLFSSL_STACK* sk, int i) { WOLFSSL_ENTER("wolfSSL_sk_value"); for (; sk != NULL && i > 0; i--) sk = sk->next; if (sk == NULL) return NULL; switch (sk->type) { case STACK_TYPE_X509: return (void*)sk->data.x509; case STACK_TYPE_GEN_NAME: return (void*)sk->data.gn; case STACK_TYPE_BIO: return (void*)sk->data.bio; case STACK_TYPE_OBJ: return (void*)sk->data.obj; case STACK_TYPE_STRING: return (void*)sk->data.string; case STACK_TYPE_CIPHER: return (void*)&sk->data.cipher; case STACK_TYPE_ACCESS_DESCRIPTION: return (void*)sk->data.access; case STACK_TYPE_X509_EXT: return (void*)sk->data.ext; case STACK_TYPE_X509_REQ_ATTR: return (void*)sk->data.generic; case STACK_TYPE_NULL: return (void*)sk->data.generic; case STACK_TYPE_X509_NAME: return (void*)sk->data.name; case STACK_TYPE_X509_NAME_ENTRY: return (void*)sk->data.name_entry; case STACK_TYPE_CONF_VALUE: #ifdef OPENSSL_EXTRA return (void*)sk->data.conf; #else return NULL; #endif case STACK_TYPE_X509_INFO: return (void*)sk->data.info; case STACK_TYPE_BY_DIR_entry: return (void*)sk->data.dir_entry; case STACK_TYPE_BY_DIR_hash: return (void*)sk->data.dir_hash; case STACK_TYPE_X509_OBJ: return (void*)sk->data.x509_obj; case STACK_TYPE_DIST_POINT: return (void*)sk->data.dp; case STACK_TYPE_X509_CRL: return (void*)sk->data.crl; default: return (void*)sk->data.generic; } } /* copies over data of "in" to "out" */ static void wolfSSL_CIPHER_copy(WOLFSSL_CIPHER* in, WOLFSSL_CIPHER* out) { if (in == NULL || out == NULL) return; *out = *in; } WOLFSSL_STACK* wolfSSL_sk_dup(WOLFSSL_STACK* sk) { WOLFSSL_STACK* ret = NULL; WOLFSSL_STACK* last = NULL; WOLFSSL_ENTER("wolfSSL_sk_dup"); while (sk) { WOLFSSL_STACK* cur = wolfSSL_sk_new_node(sk->heap); if (!cur) { WOLFSSL_MSG("wolfSSL_sk_new_node error"); goto error; } if (!ret) { /* Set first node */ ret = cur; } if (last) { last->next = cur; } XMEMCPY(cur, sk, sizeof(WOLFSSL_STACK)); /* We will allocate new memory for this */ XMEMSET(&cur->data, 0, sizeof(cur->data)); cur->next = NULL; switch (sk->type) { case STACK_TYPE_X509: if (!sk->data.x509) break; cur->data.x509 = wolfSSL_X509_dup(sk->data.x509); if (!cur->data.x509) { WOLFSSL_MSG("wolfSSL_X509_dup error"); goto error; } break; case STACK_TYPE_CIPHER: wolfSSL_CIPHER_copy(&sk->data.cipher, &cur->data.cipher); break; case STACK_TYPE_GEN_NAME: if (!sk->data.gn) break; cur->data.gn = wolfSSL_GENERAL_NAME_dup(sk->data.gn); if (!cur->data.gn) { WOLFSSL_MSG("wolfSSL_GENERAL_NAME_new error"); goto error; } break; case STACK_TYPE_OBJ: if (!sk->data.obj) break; cur->data.obj = wolfSSL_ASN1_OBJECT_dup(sk->data.obj); if (!cur->data.obj) { WOLFSSL_MSG("wolfSSL_ASN1_OBJECT_dup error"); goto error; } break; case STACK_TYPE_BIO: case STACK_TYPE_STRING: case STACK_TYPE_ACCESS_DESCRIPTION: case STACK_TYPE_X509_EXT: case STACK_TYPE_X509_REQ_ATTR: case STACK_TYPE_NULL: case STACK_TYPE_X509_NAME: case STACK_TYPE_X509_NAME_ENTRY: case STACK_TYPE_CONF_VALUE: case STACK_TYPE_X509_INFO: case STACK_TYPE_BY_DIR_entry: case STACK_TYPE_BY_DIR_hash: case STACK_TYPE_X509_OBJ: case STACK_TYPE_DIST_POINT: case STACK_TYPE_X509_CRL: default: WOLFSSL_MSG("Unsupported stack type"); goto error; } sk = sk->next; last = cur; } return ret; error: if (ret) { wolfSSL_sk_GENERAL_NAME_free(ret); } return NULL; } /* Free the just the stack structure */ void wolfSSL_sk_free(WOLFSSL_STACK* sk) { WOLFSSL_ENTER("wolfSSL_sk_free"); while (sk != NULL) { WOLFSSL_STACK* next = sk->next; XFREE(sk, NULL, DYNAMIC_TYPE_OPENSSL); sk = next; } } /* Frees each node in the stack and frees the stack. */ void wolfSSL_sk_GENERIC_pop_free(WOLFSSL_STACK* sk, void (*f) (void*)) { WOLFSSL_ENTER("wolfSSL_sk_GENERIC_pop_free"); wolfSSL_sk_pop_free(sk, (wolfSSL_sk_freefunc)f); } /* return 1 on success 0 on fail */ int wolfSSL_sk_GENERIC_push(WOLFSSL_STACK* sk, void* generic) { WOLFSSL_ENTER("wolfSSL_sk_GENERIC_push"); return wolfSSL_sk_push(sk, generic); } void wolfSSL_sk_GENERIC_free(WOLFSSL_STACK* sk) { wolfSSL_sk_free(sk); } /* Free all nodes in a stack including the pushed objects */ void wolfSSL_sk_pop_free(WOLF_STACK_OF(WOLFSSL_ASN1_OBJECT)* sk, wolfSSL_sk_freefunc func) { WOLFSSL_ENTER("wolfSSL_sk_pop_free"); if (sk == NULL) { /* pop_free can be called with NULL, do not print bad argument */ return; } #if defined(WOLFSSL_QT) /* In Qt v15.5, it calls OPENSSL_sk_free(xxx, OPENSSL_sk_free). * By using OPENSSL_sk_free for free causes access violation. * Therefore, switching free func to wolfSSL_ACCESS_DESCRIPTION_free * is needed even the func isn't NULL. */ if (sk->type == STACK_TYPE_ACCESS_DESCRIPTION) { func = (wolfSSL_sk_freefunc)wolfSSL_ACCESS_DESCRIPTION_free; } #endif if (func == NULL) { switch(sk->type) { case STACK_TYPE_ACCESS_DESCRIPTION: #if defined(OPENSSL_ALL) func = (wolfSSL_sk_freefunc)wolfSSL_ACCESS_DESCRIPTION_free; #endif break; case STACK_TYPE_X509: func = (wolfSSL_sk_freefunc)wolfSSL_X509_free; break; case STACK_TYPE_X509_OBJ: #ifdef OPENSSL_ALL func = (wolfSSL_sk_freefunc)wolfSSL_X509_OBJECT_free; #endif break; case STACK_TYPE_OBJ: func = (wolfSSL_sk_freefunc)wolfSSL_ASN1_OBJECT_free; break; case STACK_TYPE_DIST_POINT: #ifdef OPENSSL_EXTRA func = (wolfSSL_sk_freefunc)wolfSSL_DIST_POINT_free; #endif break; case STACK_TYPE_GEN_NAME: func = (wolfSSL_sk_freefunc)wolfSSL_GENERAL_NAME_free; break; case STACK_TYPE_STRING: #if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) || \ defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) func = (wolfSSL_sk_freefunc)wolfSSL_WOLFSSL_STRING_free; #endif break; case STACK_TYPE_X509_NAME: #if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) \ && !defined(WOLFCRYPT_ONLY) func = (wolfSSL_sk_freefunc)wolfSSL_X509_NAME_free; #endif break; case STACK_TYPE_X509_NAME_ENTRY: #if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) \ && !defined(WOLFCRYPT_ONLY) func = (wolfSSL_sk_freefunc)wolfSSL_X509_NAME_ENTRY_free; #endif break; case STACK_TYPE_X509_EXT: #ifdef OPENSSL_ALL func = (wolfSSL_sk_freefunc)wolfSSL_X509_EXTENSION_free; #endif break; case STACK_TYPE_X509_REQ_ATTR: #if defined(OPENSSL_ALL) && \ (defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_REQ)) func = (wolfSSL_sk_freefunc)wolfSSL_X509_ATTRIBUTE_free; #endif break; case STACK_TYPE_CONF_VALUE: #if defined(OPENSSL_ALL) func = (wolfSSL_sk_freefunc)wolfSSL_X509V3_conf_free; #endif break; case STACK_TYPE_X509_INFO: #if defined(OPENSSL_ALL) func = (wolfSSL_sk_freefunc)wolfSSL_X509_INFO_free; #endif break; case STACK_TYPE_BIO: #if !defined(NO_BIO) && defined(OPENSSL_EXTRA) func = (wolfSSL_sk_freefunc)wolfSSL_BIO_vfree; #endif break; case STACK_TYPE_BY_DIR_entry: #if defined(OPENSSL_ALL) && !defined(NO_FILESYSTEM) && !defined(NO_WOLFSSL_DIR) func = (wolfSSL_sk_freefunc)wolfSSL_BY_DIR_entry_free; #endif break; case STACK_TYPE_BY_DIR_hash: #if defined(OPENSSL_ALL) && !defined(NO_FILESYSTEM) && !defined(NO_WOLFSSL_DIR) func = (wolfSSL_sk_freefunc)wolfSSL_BY_DIR_HASH_free; #endif break; case STACK_TYPE_X509_CRL: #if defined(HAVE_CRL) && (defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)) func = (wolfSSL_sk_freefunc)wolfSSL_X509_CRL_free; #endif break; case STACK_TYPE_CIPHER: case STACK_TYPE_NULL: default: break; } } while (sk != NULL) { WOLFSSL_STACK* next = sk->next; if (func != NULL) { if (sk->type != STACK_TYPE_CIPHER) func(sk->data.generic); } XFREE(sk, NULL, DYNAMIC_TYPE_OPENSSL); sk = next; } } /* Creates and returns a new null stack. */ WOLFSSL_STACK* wolfSSL_sk_new_null(void) { WOLFSSL_STACK* sk; WOLFSSL_ENTER("wolfSSL_sk_new_null"); sk = (WOLFSSL_STACK*)XMALLOC(sizeof(WOLFSSL_STACK), NULL, DYNAMIC_TYPE_OPENSSL); if (sk == NULL) { WOLFSSL_MSG("WOLFSSL_STACK memory error"); return NULL; } XMEMSET(sk, 0, sizeof(WOLFSSL_STACK)); sk->type = STACK_TYPE_NULL; return sk; } int wolfSSL_sk_SSL_COMP_num(WOLF_STACK_OF(WOLFSSL_COMP)* sk) { if (sk == NULL) return 0; return (int)sk->num; } #endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */ #if !defined(NO_SESSION_CACHE) && (defined(OPENSSL_EXTRA) || \ defined(HAVE_EXT_CACHE)) /* stunnel 4.28 needs * * Callback that is called if a session tries to resume but could not find * the session to resume it. */ void wolfSSL_CTX_sess_set_get_cb(WOLFSSL_CTX* ctx, WOLFSSL_SESSION*(*f)(WOLFSSL*, const unsigned char*, int, int*)) { if (ctx == NULL) return; #ifdef HAVE_EXT_CACHE ctx->get_sess_cb = f; #else (void)f; #endif } void wolfSSL_CTX_sess_set_new_cb(WOLFSSL_CTX* ctx, int (*f)(WOLFSSL*, WOLFSSL_SESSION*)) { if (ctx == NULL) return; #ifdef HAVE_EXT_CACHE ctx->new_sess_cb = f; #else (void)f; #endif } void wolfSSL_CTX_sess_set_remove_cb(WOLFSSL_CTX* ctx, void (*f)(WOLFSSL_CTX*, WOLFSSL_SESSION*)) { if (ctx == NULL) return; #if defined(HAVE_EXT_CACHE) || defined(HAVE_EX_DATA) ctx->rem_sess_cb = f; #else (void)f; #endif } /* * * Note: It is expected that the importing and exporting function have been * built with the same settings. For example if session tickets was * enabled with the wolfSSL library exporting a session then it is * expected to be turned on with the wolfSSL library importing the session. */ int wolfSSL_i2d_SSL_SESSION(WOLFSSL_SESSION* sess, unsigned char** p) { int size = 0; #ifdef HAVE_EXT_CACHE int idx = 0; #ifdef SESSION_CERTS int i; #endif unsigned char *data; WOLFSSL_ENTER("wolfSSL_i2d_SSL_SESSION"); sess = ClientSessionToSession(sess); if (sess == NULL) { return BAD_FUNC_ARG; } /* side | bornOn | timeout | sessionID len | sessionID | masterSecret | * haveEMS */ size += OPAQUE8_LEN + OPAQUE32_LEN + OPAQUE32_LEN + OPAQUE8_LEN + sess->sessionIDSz + SECRET_LEN + OPAQUE8_LEN; /* altSessionID */ size += OPAQUE8_LEN + (sess->haveAltSessionID ? ID_LEN : 0); #ifdef SESSION_CERTS /* Peer chain */ size += OPAQUE8_LEN; for (i = 0; i < sess->chain.count; i++) size += OPAQUE16_LEN + sess->chain.certs[i].length; #endif #if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \ defined(HAVE_SESSION_TICKET)) /* Protocol version */ size += OPAQUE16_LEN; #endif #if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \ (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) /* cipher suite */ size += OPAQUE16_LEN; #endif #ifndef NO_CLIENT_CACHE /* ServerID len | ServerID */ size += OPAQUE16_LEN + sess->idLen; #endif #ifdef OPENSSL_EXTRA /* session context ID len | session context ID */ size += OPAQUE8_LEN + sess->sessionCtxSz; #endif #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) /* peerVerifyRet */ size += OPAQUE8_LEN; #endif #ifdef WOLFSSL_TLS13 /* namedGroup */ size += OPAQUE16_LEN; #endif #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) #ifdef WOLFSSL_TLS13 /* ticketSeen | ticketAdd */ size += OPAQUE32_LEN + OPAQUE32_LEN; /* ticketNonce */ size += OPAQUE8_LEN + sess->ticketNonce.len; #endif #ifdef WOLFSSL_EARLY_DATA size += OPAQUE32_LEN; #endif #endif #ifdef HAVE_SESSION_TICKET /* ticket len | ticket */ size += OPAQUE16_LEN + sess->ticketLen; #endif if (p != NULL) { if (*p == NULL) *p = (unsigned char*)XMALLOC(size, NULL, DYNAMIC_TYPE_OPENSSL); if (*p == NULL) return 0; data = *p; data[idx++] = sess->side; c32toa(sess->bornOn, data + idx); idx += OPAQUE32_LEN; c32toa(sess->timeout, data + idx); idx += OPAQUE32_LEN; data[idx++] = sess->sessionIDSz; XMEMCPY(data + idx, sess->sessionID, sess->sessionIDSz); idx += sess->sessionIDSz; XMEMCPY(data + idx, sess->masterSecret, SECRET_LEN); idx += SECRET_LEN; data[idx++] = (byte)sess->haveEMS; data[idx++] = sess->haveAltSessionID ? ID_LEN : 0; if (sess->haveAltSessionID) { XMEMCPY(data + idx, sess->altSessionID, ID_LEN); idx += ID_LEN; } #ifdef SESSION_CERTS data[idx++] = (byte)sess->chain.count; for (i = 0; i < sess->chain.count; i++) { c16toa((word16)sess->chain.certs[i].length, data + idx); idx += OPAQUE16_LEN; XMEMCPY(data + idx, sess->chain.certs[i].buffer, sess->chain.certs[i].length); idx += sess->chain.certs[i].length; } #endif #if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \ defined(HAVE_SESSION_TICKET)) data[idx++] = sess->version.major; data[idx++] = sess->version.minor; #endif #if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \ (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) data[idx++] = sess->cipherSuite0; data[idx++] = sess->cipherSuite; #endif #ifndef NO_CLIENT_CACHE c16toa(sess->idLen, data + idx); idx += OPAQUE16_LEN; XMEMCPY(data + idx, sess->serverID, sess->idLen); idx += sess->idLen; #endif #ifdef OPENSSL_EXTRA data[idx++] = sess->sessionCtxSz; XMEMCPY(data + idx, sess->sessionCtx, sess->sessionCtxSz); idx += sess->sessionCtxSz; #endif #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) data[idx++] = sess->peerVerifyRet; #endif #ifdef WOLFSSL_TLS13 c16toa(sess->namedGroup, data + idx); idx += OPAQUE16_LEN; #endif #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) #ifdef WOLFSSL_TLS13 c32toa(sess->ticketSeen, data + idx); idx += OPAQUE32_LEN; c32toa(sess->ticketAdd, data + idx); idx += OPAQUE32_LEN; data[idx++] = sess->ticketNonce.len; XMEMCPY(data + idx, sess->ticketNonce.data, sess->ticketNonce.len); idx += sess->ticketNonce.len; #endif #ifdef WOLFSSL_EARLY_DATA c32toa(sess->maxEarlyDataSz, data + idx); idx += OPAQUE32_LEN; #endif #endif #ifdef HAVE_SESSION_TICKET c16toa(sess->ticketLen, data + idx); idx += OPAQUE16_LEN; XMEMCPY(data + idx, sess->ticket, sess->ticketLen); idx += sess->ticketLen; #endif } #endif (void)sess; (void)p; #ifdef HAVE_EXT_CACHE (void)idx; #endif return size; } /* TODO: no function to free new session. * * Note: It is expected that the importing and exporting function have been * built with the same settings. For example if session tickets was * enabled with the wolfSSL library exporting a session then it is * expected to be turned on with the wolfSSL library importing the session. */ WOLFSSL_SESSION* wolfSSL_d2i_SSL_SESSION(WOLFSSL_SESSION** sess, const unsigned char** p, long i) { WOLFSSL_SESSION* s = NULL; int ret = 0; #if defined(HAVE_EXT_CACHE) int idx; byte* data; #ifdef SESSION_CERTS int j; word16 length; #endif #endif /* HAVE_EXT_CACHE */ (void)p; (void)i; (void)ret; (void)sess; #ifdef HAVE_EXT_CACHE if (p == NULL || *p == NULL) return NULL; s = wolfSSL_SESSION_new(); if (s == NULL) return NULL; idx = 0; data = (byte*)*p; /* side | bornOn | timeout | sessionID len */ if (i < OPAQUE8_LEN + OPAQUE32_LEN + OPAQUE32_LEN + OPAQUE8_LEN) { ret = BUFFER_ERROR; goto end; } s->side = data[idx++]; ato32(data + idx, &s->bornOn); idx += OPAQUE32_LEN; ato32(data + idx, &s->timeout); idx += OPAQUE32_LEN; s->sessionIDSz = data[idx++]; /* sessionID | secret | haveEMS | haveAltSessionID */ if (i - idx < s->sessionIDSz + SECRET_LEN + OPAQUE8_LEN + OPAQUE8_LEN) { ret = BUFFER_ERROR; goto end; } XMEMCPY(s->sessionID, data + idx, s->sessionIDSz); idx += s->sessionIDSz; XMEMCPY(s->masterSecret, data + idx, SECRET_LEN); idx += SECRET_LEN; s->haveEMS = data[idx++]; if (data[idx] != ID_LEN && data[idx] != 0) { ret = BUFFER_ERROR; goto end; } s->haveAltSessionID = data[idx++] == ID_LEN; /* altSessionID */ if (s->haveAltSessionID) { if (i - idx < ID_LEN) { ret = BUFFER_ERROR; goto end; } XMEMCPY(s->altSessionID, data + idx, ID_LEN); idx += ID_LEN; } #ifdef SESSION_CERTS /* Certificate chain */ if (i - idx == 0) { ret = BUFFER_ERROR; goto end; } s->chain.count = data[idx++]; for (j = 0; j < s->chain.count; j++) { if (i - idx < OPAQUE16_LEN) { ret = BUFFER_ERROR; goto end; } ato16(data + idx, &length); idx += OPAQUE16_LEN; s->chain.certs[j].length = length; if (i - idx < length) { ret = BUFFER_ERROR; goto end; } XMEMCPY(s->chain.certs[j].buffer, data + idx, length); idx += length; } #endif #if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \ defined(HAVE_SESSION_TICKET)) /* Protocol Version */ if (i - idx < OPAQUE16_LEN) { ret = BUFFER_ERROR; goto end; } s->version.major = data[idx++]; s->version.minor = data[idx++]; #endif #if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \ (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) /* Cipher suite */ if (i - idx < OPAQUE16_LEN) { ret = BUFFER_ERROR; goto end; } s->cipherSuite0 = data[idx++]; s->cipherSuite = data[idx++]; #endif #ifndef NO_CLIENT_CACHE /* ServerID len */ if (i - idx < OPAQUE16_LEN) { ret = BUFFER_ERROR; goto end; } ato16(data + idx, &s->idLen); idx += OPAQUE16_LEN; /* ServerID */ if (i - idx < s->idLen) { ret = BUFFER_ERROR; goto end; } XMEMCPY(s->serverID, data + idx, s->idLen); idx += s->idLen; #endif #ifdef OPENSSL_EXTRA /* byte for length of session context ID */ if (i - idx < OPAQUE8_LEN) { ret = BUFFER_ERROR; goto end; } s->sessionCtxSz = data[idx++]; /* app session context ID */ if (i - idx < s->sessionCtxSz) { ret = BUFFER_ERROR; goto end; } XMEMCPY(s->sessionCtx, data + idx, s->sessionCtxSz); idx += s->sessionCtxSz; #endif #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) /* byte for peerVerifyRet */ if (i - idx < OPAQUE8_LEN) { ret = BUFFER_ERROR; goto end; } s->peerVerifyRet = data[idx++]; #endif #ifdef WOLFSSL_TLS13 if (i - idx < OPAQUE16_LEN) { ret = BUFFER_ERROR; goto end; } ato16(data + idx, &s->namedGroup); idx += OPAQUE16_LEN; #endif #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) #ifdef WOLFSSL_TLS13 if (i - idx < (OPAQUE32_LEN * 2)) { ret = BUFFER_ERROR; goto end; } ato32(data + idx, &s->ticketSeen); idx += OPAQUE32_LEN; ato32(data + idx, &s->ticketAdd); idx += OPAQUE32_LEN; if (i - idx < OPAQUE8_LEN) { ret = BUFFER_ERROR; goto end; } s->ticketNonce.len = data[idx++]; if (i - idx < s->ticketNonce.len) { ret = BUFFER_ERROR; goto end; } XMEMCPY(s->ticketNonce.data, data + idx, s->ticketNonce.len); idx += s->ticketNonce.len; #endif #ifdef WOLFSSL_EARLY_DATA if (i - idx < OPAQUE32_LEN) { ret = BUFFER_ERROR; goto end; } ato32(data + idx, &s->maxEarlyDataSz); idx += OPAQUE32_LEN; #endif #endif #ifdef HAVE_SESSION_TICKET /* ticket len */ if (i - idx < OPAQUE16_LEN) { ret = BUFFER_ERROR; goto end; } ato16(data + idx, &s->ticketLen); idx += OPAQUE16_LEN; /* Dispose of ol dynamic ticket and ensure space for new ticket. */ if (s->ticketLenAlloc > 0) { XFREE(s->ticket, NULL, DYNAMIC_TYPE_SESSION_TICK); } if (s->ticketLen <= SESSION_TICKET_LEN) s->ticket = s->_staticTicket; else { s->ticket = (byte*)XMALLOC(s->ticketLen, NULL, DYNAMIC_TYPE_SESSION_TICK); if (s->ticket == NULL) { ret = MEMORY_ERROR; goto end; } s->ticketLenAlloc = (word16)s->ticketLen; } /* ticket */ if (i - idx < s->ticketLen) { ret = BUFFER_ERROR; goto end; } XMEMCPY(s->ticket, data + idx, s->ticketLen); idx += s->ticketLen; #endif (void)idx; if (sess != NULL) { *sess = s; } *p += idx; end: if (ret != 0 && (sess == NULL || *sess != s)) { wolfSSL_SESSION_free(s); s = NULL; } #endif /* HAVE_EXT_CACHE */ return s; } /* Check if there is a session ticket associated with this WOLFSSL_SESSION. * * sess - pointer to WOLFSSL_SESSION struct * * Returns 1 if has session ticket, otherwise 0 */ int wolfSSL_SESSION_has_ticket(const WOLFSSL_SESSION* sess) { WOLFSSL_ENTER("wolfSSL_SESSION_has_ticket"); #ifdef HAVE_SESSION_TICKET sess = ClientSessionToSession(sess); if (sess) { if ((sess->ticketLen > 0) && (sess->ticket != NULL)) { return WOLFSSL_SUCCESS; } } #else (void)sess; #endif return WOLFSSL_FAILURE; } unsigned long wolfSSL_SESSION_get_ticket_lifetime_hint( const WOLFSSL_SESSION* sess) { WOLFSSL_ENTER("wolfSSL_SESSION_get_ticket_lifetime_hint"); sess = ClientSessionToSession(sess); if (sess) { return sess->timeout; } return 0; } long wolfSSL_SESSION_get_timeout(const WOLFSSL_SESSION* sess) { long timeout = 0; WOLFSSL_ENTER("wolfSSL_SESSION_get_timeout"); sess = ClientSessionToSession(sess); if (sess) timeout = sess->timeout; return timeout; } long wolfSSL_SESSION_get_time(const WOLFSSL_SESSION* sess) { long bornOn = 0; WOLFSSL_ENTER("wolfSSL_SESSION_get_time"); sess = ClientSessionToSession(sess); if (sess) bornOn = sess->bornOn; return bornOn; } long wolfSSL_SSL_SESSION_set_timeout(WOLFSSL_SESSION* ses, long t) { word32 tmptime; ses = ClientSessionToSession(ses); if (ses == NULL || t < 0) { return BAD_FUNC_ARG; } tmptime = t & 0xFFFFFFFF; ses->timeout = tmptime; return WOLFSSL_SUCCESS; } #endif /* !NO_SESSION_CACHE && OPENSSL_EXTRA || HAVE_EXT_CACHE */ #ifdef OPENSSL_EXTRA #if defined(HAVE_EX_DATA) && !defined(NO_FILESYSTEM) int wolfSSL_cmp_peer_cert_to_file(WOLFSSL* ssl, const char *fname) { int ret = WOLFSSL_FATAL_ERROR; WOLFSSL_ENTER("wolfSSL_cmp_peer_cert_to_file"); if (ssl != NULL && fname != NULL) { #ifdef WOLFSSL_SMALL_STACK byte staticBuffer[1]; /* force heap usage */ #else byte staticBuffer[FILE_BUFFER_SIZE]; #endif byte* myBuffer = staticBuffer; int dynamic = 0; XFILE file; long sz = 0; WOLFSSL_CTX* ctx = ssl->ctx; WOLFSSL_X509* peer_cert = &ssl->peerCert; DerBuffer* fileDer = NULL; file = XFOPEN(fname, "rb"); if (file == XBADFILE) return WOLFSSL_BAD_FILE; if (XFSEEK(file, 0, XSEEK_END) != 0) { XFCLOSE(file); return WOLFSSL_BAD_FILE; } sz = XFTELL(file); XREWIND(file); if (sz > MAX_WOLFSSL_FILE_SIZE || sz < 0) { WOLFSSL_MSG("cmp_peer_cert_to_file size error"); XFCLOSE(file); return WOLFSSL_BAD_FILE; } if (sz > (long)sizeof(staticBuffer)) { WOLFSSL_MSG("Getting dynamic buffer"); myBuffer = (byte*)XMALLOC(sz, ctx->heap, DYNAMIC_TYPE_FILE); dynamic = 1; } if ((myBuffer != NULL) && (sz > 0) && (XFREAD(myBuffer, 1, sz, file) == (size_t)sz) && (PemToDer(myBuffer, (long)sz, CERT_TYPE, &fileDer, ctx->heap, NULL, NULL) == 0) && (fileDer->length != 0) && (fileDer->length == peer_cert->derCert->length) && (XMEMCMP(peer_cert->derCert->buffer, fileDer->buffer, fileDer->length) == 0)) { ret = 0; } FreeDer(&fileDer); if (dynamic) XFREE(myBuffer, ctx->heap, DYNAMIC_TYPE_FILE); XFCLOSE(file); } return ret; } #endif #endif /* OPENSSL_EXTRA */ #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) const WOLFSSL_ObjectInfo wolfssl_object_info[] = { #ifndef NO_CERTS /* oidCertExtType */ { NID_basic_constraints, BASIC_CA_OID, oidCertExtType, "basicConstraints", "X509v3 Basic Constraints"}, { NID_subject_alt_name, ALT_NAMES_OID, oidCertExtType, "subjectAltName", "X509v3 Subject Alternative Name"}, { NID_crl_distribution_points, CRL_DIST_OID, oidCertExtType, "crlDistributionPoints", "X509v3 CRL Distribution Points"}, { NID_info_access, AUTH_INFO_OID, oidCertExtType, "authorityInfoAccess", "Authority Information Access"}, { NID_authority_key_identifier, AUTH_KEY_OID, oidCertExtType, "authorityKeyIdentifier", "X509v3 Authority Key Identifier"}, { NID_subject_key_identifier, SUBJ_KEY_OID, oidCertExtType, "subjectKeyIdentifier", "X509v3 Subject Key Identifier"}, { NID_key_usage, KEY_USAGE_OID, oidCertExtType, "keyUsage", "X509v3 Key Usage"}, { NID_inhibit_any_policy, INHIBIT_ANY_OID, oidCertExtType, "inhibitAnyPolicy", "X509v3 Inhibit Any Policy"}, { NID_ext_key_usage, EXT_KEY_USAGE_OID, oidCertExtType, "extendedKeyUsage", "X509v3 Extended Key Usage"}, { NID_name_constraints, NAME_CONS_OID, oidCertExtType, "nameConstraints", "X509v3 Name Constraints"}, { NID_certificate_policies, CERT_POLICY_OID, oidCertExtType, "certificatePolicies", "X509v3 Certificate Policies"}, /* oidCertAuthInfoType */ { NID_ad_OCSP, AIA_OCSP_OID, oidCertAuthInfoType, "OCSP", "OCSP"}, { NID_ad_ca_issuers, AIA_CA_ISSUER_OID, oidCertAuthInfoType, "caIssuers", "CA Issuers"}, /* oidCertPolicyType */ { NID_any_policy, CP_ANY_OID, oidCertPolicyType, "anyPolicy", "X509v3 Any Policy"}, /* oidCertAltNameType */ { NID_hw_name_oid, HW_NAME_OID, oidCertAltNameType, "Hardware name",""}, /* oidCertKeyUseType */ { NID_anyExtendedKeyUsage, EKU_ANY_OID, oidCertKeyUseType, "anyExtendedKeyUsage", "Any Extended Key Usage"}, { EKU_SERVER_AUTH_OID, EKU_SERVER_AUTH_OID, oidCertKeyUseType, "serverAuth", "TLS Web Server Authentication"}, { EKU_CLIENT_AUTH_OID, EKU_CLIENT_AUTH_OID, oidCertKeyUseType, "clientAuth", "TLS Web Client Authentication"}, { EKU_OCSP_SIGN_OID, EKU_OCSP_SIGN_OID, oidCertKeyUseType, "OCSPSigning", "OCSP Signing"}, /* oidCertNameType */ { NID_commonName, NID_commonName, oidCertNameType, "CN", "commonName"}, { NID_surname, NID_surname, oidCertNameType, "SN", "surname"}, { NID_serialNumber, NID_serialNumber, oidCertNameType, "serialNumber", "serialNumber"}, { NID_userId, NID_userId, oidCertNameType, "UID", "userid"}, { NID_countryName, NID_countryName, oidCertNameType, "C", "countryName"}, { NID_localityName, NID_localityName, oidCertNameType, "L", "localityName"}, { NID_stateOrProvinceName, NID_stateOrProvinceName, oidCertNameType, "ST", "stateOrProvinceName"}, { NID_streetAddress, NID_streetAddress, oidCertNameType, "street", "streetAddress"}, { NID_organizationName, NID_organizationName, oidCertNameType, "O", "organizationName"}, { NID_organizationalUnitName, NID_organizationalUnitName, oidCertNameType, "OU", "organizationalUnitName"}, { NID_emailAddress, NID_emailAddress, oidCertNameType, "emailAddress", "emailAddress"}, { NID_domainComponent, NID_domainComponent, oidCertNameType, "DC", "domainComponent"}, { NID_favouriteDrink, NID_favouriteDrink, oidCertNameType, "favouriteDrink", "favouriteDrink"}, { NID_businessCategory, NID_businessCategory, oidCertNameType, "businessCategory", "businessCategory"}, { NID_jurisdictionCountryName, NID_jurisdictionCountryName, oidCertNameType, "jurisdictionC", "jurisdictionCountryName"}, { NID_jurisdictionStateOrProvinceName, NID_jurisdictionStateOrProvinceName, oidCertNameType, "jurisdictionST", "jurisdictionStateOrProvinceName"}, { NID_postalCode, NID_postalCode, oidCertNameType, "postalCode", "postalCode"}, { NID_userId, NID_userId, oidCertNameType, "UID", "userId"}, #ifdef WOLFSSL_CERT_REQ { NID_pkcs9_challengePassword, CHALLENGE_PASSWORD_OID, oidCsrAttrType, "challengePassword", "challengePassword"}, { NID_pkcs9_contentType, PKCS9_CONTENT_TYPE_OID, oidCsrAttrType, "contentType", "contentType" }, { NID_pkcs9_unstructuredName, UNSTRUCTURED_NAME_OID, oidCsrAttrType, "unstructuredName", "unstructuredName" }, { NID_surname, SURNAME_OID, oidCsrAttrType, "surname", "surname" }, { NID_givenName, GIVEN_NAME_OID, oidCsrAttrType, "givenName", "givenName" }, { NID_initials, INITIALS_OID, oidCsrAttrType, "initials", "initials" }, { NID_dnQualifier, DNQUALIFIER_OID, oidCsrAttrType, "dnQualifer", "dnQualifier" }, #endif #endif #ifdef OPENSSL_EXTRA /* OPENSSL_EXTRA_X509_SMALL only needs the above */ /* oidHashType */ #ifdef WOLFSSL_MD2 { NID_md2, MD2h, oidHashType, "MD2", "md2"}, #endif #ifdef WOLFSSL_MD5 { NID_md5, MD5h, oidHashType, "MD5", "md5"}, #endif #ifndef NO_SHA { NID_sha1, SHAh, oidHashType, "SHA1", "sha1"}, #endif #ifdef WOLFSSL_SHA224 { NID_sha224, SHA224h, oidHashType, "SHA224", "sha224"}, #endif #ifndef NO_SHA256 { NID_sha256, SHA256h, oidHashType, "SHA256", "sha256"}, #endif #ifdef WOLFSSL_SHA384 { NID_sha384, SHA384h, oidHashType, "SHA384", "sha384"}, #endif #ifdef WOLFSSL_SHA512 { NID_sha512, SHA512h, oidHashType, "SHA512", "sha512"}, #endif #ifdef WOLFSSL_SHA3 #ifndef WOLFSSL_NOSHA3_224 { NID_sha3_224, SHA3_224h, oidHashType, "SHA3-224", "sha3-224"}, #endif #ifndef WOLFSSL_NOSHA3_256 { NID_sha3_256, SHA3_256h, oidHashType, "SHA3-256", "sha3-256"}, #endif #ifndef WOLFSSL_NOSHA3_384 { NID_sha3_384, SHA3_384h, oidHashType, "SHA3-384", "sha3-384"}, #endif #ifndef WOLFSSL_NOSHA3_512 { NID_sha3_512, SHA3_512h, oidHashType, "SHA3-512", "sha3-512"}, #endif #endif /* WOLFSSL_SHA3 */ /* oidSigType */ #ifndef NO_DSA #ifndef NO_SHA { NID_dsaWithSHA1, CTC_SHAwDSA, oidSigType, "DSA-SHA1", "dsaWithSHA1"}, { NID_dsa_with_SHA256, CTC_SHA256wDSA, oidSigType, "dsa_with_SHA256", "dsa_with_SHA256"}, #endif #endif /* NO_DSA */ #ifndef NO_RSA #ifdef WOLFSSL_MD2 { NID_md2WithRSAEncryption, CTC_MD2wRSA, oidSigType, "RSA-MD2", "md2WithRSAEncryption"}, #endif #ifndef NO_MD5 { NID_md5WithRSAEncryption, CTC_MD5wRSA, oidSigType, "RSA-MD5", "md5WithRSAEncryption"}, #endif #ifndef NO_SHA { NID_sha1WithRSAEncryption, CTC_SHAwRSA, oidSigType, "RSA-SHA1", "sha1WithRSAEncryption"}, #endif #ifdef WOLFSSL_SHA224 { NID_sha224WithRSAEncryption, CTC_SHA224wRSA, oidSigType, "RSA-SHA224", "sha224WithRSAEncryption"}, #endif #ifndef NO_SHA256 { NID_sha256WithRSAEncryption, CTC_SHA256wRSA, oidSigType, "RSA-SHA256", "sha256WithRSAEncryption"}, #endif #ifdef WOLFSSL_SHA384 { NID_sha384WithRSAEncryption, CTC_SHA384wRSA, oidSigType, "RSA-SHA384", "sha384WithRSAEncryption"}, #endif #ifdef WOLFSSL_SHA512 { NID_sha512WithRSAEncryption, CTC_SHA512wRSA, oidSigType, "RSA-SHA512", "sha512WithRSAEncryption"}, #endif #ifdef WOLFSSL_SHA3 #ifndef WOLFSSL_NOSHA3_224 { NID_RSA_SHA3_224, CTC_SHA3_224wRSA, oidSigType, "RSA-SHA3-224", "sha3-224WithRSAEncryption"}, #endif #ifndef WOLFSSL_NOSHA3_256 { NID_RSA_SHA3_256, CTC_SHA3_256wRSA, oidSigType, "RSA-SHA3-256", "sha3-256WithRSAEncryption"}, #endif #ifndef WOLFSSL_NOSHA3_384 { NID_RSA_SHA3_384, CTC_SHA3_384wRSA, oidSigType, "RSA-SHA3-384", "sha3-384WithRSAEncryption"}, #endif #ifndef WOLFSSL_NOSHA3_512 { NID_RSA_SHA3_512, CTC_SHA3_512wRSA, oidSigType, "RSA-SHA3-512", "sha3-512WithRSAEncryption"}, #endif #endif #endif /* NO_RSA */ #ifdef HAVE_ECC #ifndef NO_SHA { NID_ecdsa_with_SHA1, CTC_SHAwECDSA, oidSigType, "ecdsa-with-SHA1", "shaWithECDSA"}, #endif #ifdef WOLFSSL_SHA224 { NID_ecdsa_with_SHA224, CTC_SHA224wECDSA, oidSigType, "ecdsa-with-SHA224","sha224WithECDSA"}, #endif #ifndef NO_SHA256 { NID_ecdsa_with_SHA256, CTC_SHA256wECDSA, oidSigType, "ecdsa-with-SHA256","sha256WithECDSA"}, #endif #ifdef WOLFSSL_SHA384 { NID_ecdsa_with_SHA384, CTC_SHA384wECDSA, oidSigType, "ecdsa-with-SHA384","sha384WithECDSA"}, #endif #ifdef WOLFSSL_SHA512 { NID_ecdsa_with_SHA512, CTC_SHA512wECDSA, oidSigType, "ecdsa-with-SHA512","sha512WithECDSA"}, #endif #ifdef WOLFSSL_SHA3 #ifndef WOLFSSL_NOSHA3_224 { NID_ecdsa_with_SHA3_224, CTC_SHA3_224wECDSA, oidSigType, "id-ecdsa-with-SHA3-224", "ecdsa_with_SHA3-224"}, #endif #ifndef WOLFSSL_NOSHA3_256 { NID_ecdsa_with_SHA3_256, CTC_SHA3_256wECDSA, oidSigType, "id-ecdsa-with-SHA3-256", "ecdsa_with_SHA3-256"}, #endif #ifndef WOLFSSL_NOSHA3_384 { NID_ecdsa_with_SHA3_384, CTC_SHA3_384wECDSA, oidSigType, "id-ecdsa-with-SHA3-384", "ecdsa_with_SHA3-384"}, #endif #ifndef WOLFSSL_NOSHA3_512 { NID_ecdsa_with_SHA3_512, CTC_SHA3_512wECDSA, oidSigType, "id-ecdsa-with-SHA3-512", "ecdsa_with_SHA3-512"}, #endif #endif #endif /* HAVE_ECC */ /* oidKeyType */ #ifndef NO_DSA { NID_dsa, DSAk, oidKeyType, "DSA", "dsaEncryption"}, #endif /* NO_DSA */ #ifndef NO_RSA { NID_rsaEncryption, RSAk, oidKeyType, "rsaEncryption", "rsaEncryption"}, #endif /* NO_RSA */ #ifdef HAVE_ECC { NID_X9_62_id_ecPublicKey, ECDSAk, oidKeyType, "id-ecPublicKey", "id-ecPublicKey"}, #endif /* HAVE_ECC */ #ifndef NO_DH { NID_dhKeyAgreement, DHk, oidKeyType, "dhKeyAgreement", "dhKeyAgreement"}, #endif #ifdef HAVE_ED448 { NID_ED448, ED448k, oidKeyType, "ED448", "ED448"}, #endif #ifdef HAVE_ED25519 { NID_ED25519, ED25519k, oidKeyType, "ED25519", "ED25519"}, #endif #ifdef HAVE_PQC { CTC_FALCON_LEVEL1, FALCON_LEVEL1k, oidKeyType, "Falcon Level 1", "Falcon Level 1"}, { CTC_FALCON_LEVEL5, FALCON_LEVEL5k, oidKeyType, "Falcon Level 5", "Falcon Level 5"}, #endif /* oidCurveType */ #ifdef HAVE_ECC { NID_X9_62_prime192v1, ECC_SECP192R1_OID, oidCurveType, "prime192v1", "prime192v1"}, { NID_X9_62_prime192v2, ECC_PRIME192V2_OID, oidCurveType, "prime192v2", "prime192v2"}, { NID_X9_62_prime192v3, ECC_PRIME192V3_OID, oidCurveType, "prime192v3", "prime192v3"}, { NID_X9_62_prime239v1, ECC_PRIME239V1_OID, oidCurveType, "prime239v1", "prime239v1"}, { NID_X9_62_prime239v2, ECC_PRIME239V2_OID, oidCurveType, "prime239v2", "prime239v2"}, { NID_X9_62_prime239v3, ECC_PRIME239V3_OID, oidCurveType, "prime239v3", "prime239v3"}, { NID_X9_62_prime256v1, ECC_SECP256R1_OID, oidCurveType, "prime256v1", "prime256v1"}, { NID_secp112r1, ECC_SECP112R1_OID, oidCurveType, "secp112r1", "secp112r1"}, { NID_secp112r2, ECC_SECP112R2_OID, oidCurveType, "secp112r2", "secp112r2"}, { NID_secp128r1, ECC_SECP128R1_OID, oidCurveType, "secp128r1", "secp128r1"}, { NID_secp128r2, ECC_SECP128R2_OID, oidCurveType, "secp128r2", "secp128r2"}, { NID_secp160r1, ECC_SECP160R1_OID, oidCurveType, "secp160r1", "secp160r1"}, { NID_secp160r2, ECC_SECP160R2_OID, oidCurveType, "secp160r2", "secp160r2"}, { NID_secp224r1, ECC_SECP224R1_OID, oidCurveType, "secp224r1", "secp224r1"}, { NID_secp384r1, ECC_SECP384R1_OID, oidCurveType, "secp384r1", "secp384r1"}, { NID_secp521r1, ECC_SECP521R1_OID, oidCurveType, "secp521r1", "secp521r1"}, { NID_secp160k1, ECC_SECP160K1_OID, oidCurveType, "secp160k1", "secp160k1"}, { NID_secp192k1, ECC_SECP192K1_OID, oidCurveType, "secp192k1", "secp192k1"}, { NID_secp224k1, ECC_SECP224K1_OID, oidCurveType, "secp224k1", "secp224k1"}, { NID_secp256k1, ECC_SECP256K1_OID, oidCurveType, "secp256k1", "secp256k1"}, { NID_brainpoolP160r1, ECC_BRAINPOOLP160R1_OID, oidCurveType, "brainpoolP160r1", "brainpoolP160r1"}, { NID_brainpoolP192r1, ECC_BRAINPOOLP192R1_OID, oidCurveType, "brainpoolP192r1", "brainpoolP192r1"}, { NID_brainpoolP224r1, ECC_BRAINPOOLP224R1_OID, oidCurveType, "brainpoolP224r1", "brainpoolP224r1"}, { NID_brainpoolP256r1, ECC_BRAINPOOLP256R1_OID, oidCurveType, "brainpoolP256r1", "brainpoolP256r1"}, { NID_brainpoolP320r1, ECC_BRAINPOOLP320R1_OID, oidCurveType, "brainpoolP320r1", "brainpoolP320r1"}, { NID_brainpoolP384r1, ECC_BRAINPOOLP384R1_OID, oidCurveType, "brainpoolP384r1", "brainpoolP384r1"}, { NID_brainpoolP512r1, ECC_BRAINPOOLP512R1_OID, oidCurveType, "brainpoolP512r1", "brainpoolP512r1"}, #endif /* HAVE_ECC */ /* oidBlkType */ #ifdef WOLFSSL_AES_128 { AES128CBCb, AES128CBCb, oidBlkType, "AES-128-CBC", "aes-128-cbc"}, #endif #ifdef WOLFSSL_AES_192 { AES192CBCb, AES192CBCb, oidBlkType, "AES-192-CBC", "aes-192-cbc"}, #endif #ifdef WOLFSSL_AES_256 { AES256CBCb, AES256CBCb, oidBlkType, "AES-256-CBC", "aes-256-cbc"}, #endif #ifndef NO_DES3 { NID_des, DESb, oidBlkType, "DES-CBC", "des-cbc"}, { NID_des3, DES3b, oidBlkType, "DES-EDE3-CBC", "des-ede3-cbc"}, #endif /* !NO_DES3 */ /* oidOcspType */ #ifdef HAVE_OCSP { NID_id_pkix_OCSP_basic, OCSP_BASIC_OID, oidOcspType, "basicOCSPResponse", "Basic OCSP Response"}, { OCSP_NONCE_OID, OCSP_NONCE_OID, oidOcspType, "Nonce", "OCSP Nonce"}, #endif /* HAVE_OCSP */ #ifndef NO_PWDBASED /* oidKdfType */ { PBKDF2_OID, PBKDF2_OID, oidKdfType, "PBKDFv2", "PBKDF2"}, /* oidPBEType */ { PBE_SHA1_RC4_128, PBE_SHA1_RC4_128, oidPBEType, "PBE-SHA1-RC4-128", "pbeWithSHA1And128BitRC4"}, { PBE_SHA1_DES, PBE_SHA1_DES, oidPBEType, "PBE-SHA1-DES", "pbeWithSHA1AndDES-CBC"}, { PBE_SHA1_DES3, PBE_SHA1_DES3, oidPBEType, "PBE-SHA1-3DES", "pbeWithSHA1And3-KeyTripleDES-CBC"}, #endif /* oidKeyWrapType */ #ifdef WOLFSSL_AES_128 { AES128_WRAP, AES128_WRAP, oidKeyWrapType, "AES-128 wrap", "aes128-wrap"}, #endif #ifdef WOLFSSL_AES_192 { AES192_WRAP, AES192_WRAP, oidKeyWrapType, "AES-192 wrap", "aes192-wrap"}, #endif #ifdef WOLFSSL_AES_256 { AES256_WRAP, AES256_WRAP, oidKeyWrapType, "AES-256 wrap", "aes256-wrap"}, #endif #ifndef NO_PKCS7 #ifndef NO_DH /* oidCmsKeyAgreeType */ #ifndef NO_SHA { dhSinglePass_stdDH_sha1kdf_scheme, dhSinglePass_stdDH_sha1kdf_scheme, oidCmsKeyAgreeType, "dhSinglePass-stdDH-sha1kdf-scheme", "dhSinglePass-stdDH-sha1kdf-scheme"}, #endif #ifdef WOLFSSL_SHA224 { dhSinglePass_stdDH_sha224kdf_scheme, dhSinglePass_stdDH_sha224kdf_scheme, oidCmsKeyAgreeType, "dhSinglePass-stdDH-sha224kdf-scheme", "dhSinglePass-stdDH-sha224kdf-scheme"}, #endif #ifndef NO_SHA256 { dhSinglePass_stdDH_sha256kdf_scheme, dhSinglePass_stdDH_sha256kdf_scheme, oidCmsKeyAgreeType, "dhSinglePass-stdDH-sha256kdf-scheme", "dhSinglePass-stdDH-sha256kdf-scheme"}, #endif #ifdef WOLFSSL_SHA384 { dhSinglePass_stdDH_sha384kdf_scheme, dhSinglePass_stdDH_sha384kdf_scheme, oidCmsKeyAgreeType, "dhSinglePass-stdDH-sha384kdf-scheme", "dhSinglePass-stdDH-sha384kdf-scheme"}, #endif #ifdef WOLFSSL_SHA512 { dhSinglePass_stdDH_sha512kdf_scheme, dhSinglePass_stdDH_sha512kdf_scheme, oidCmsKeyAgreeType, "dhSinglePass-stdDH-sha512kdf-scheme", "dhSinglePass-stdDH-sha512kdf-scheme"}, #endif #endif #endif #if defined(WOLFSSL_APACHE_HTTPD) /* "1.3.6.1.5.5.7.8.7" */ { NID_id_on_dnsSRV, NID_id_on_dnsSRV, oidCertNameType, WOLFSSL_SN_DNS_SRV, WOLFSSL_LN_DNS_SRV }, /* "1.3.6.1.4.1.311.20.2.3" */ { NID_ms_upn, WOLFSSL_MS_UPN_SUM, oidCertExtType, WOLFSSL_SN_MS_UPN, WOLFSSL_LN_MS_UPN }, /* "1.3.6.1.5.5.7.1.24" */ { NID_tlsfeature, WOLFSSL_TLS_FEATURE_SUM, oidTlsExtType, WOLFSSL_SN_TLS_FEATURE, WOLFSSL_LN_TLS_FEATURE }, #endif #endif /* OPENSSL_EXTRA */ }; #define WOLFSSL_OBJECT_INFO_SZ \ (sizeof(wolfssl_object_info) / sizeof(*wolfssl_object_info)) const size_t wolfssl_object_info_sz = WOLFSSL_OBJECT_INFO_SZ; #endif #ifdef OPENSSL_EXTRA WOLFSSL_ASN1_INTEGER* wolfSSL_BN_to_ASN1_INTEGER(const WOLFSSL_BIGNUM *bn, WOLFSSL_ASN1_INTEGER *ai) { WOLFSSL_ASN1_INTEGER* a; int len; const int extraTagSz = MAX_LENGTH_SZ + 1; byte intTag[MAX_LENGTH_SZ + 1]; int idx = 0; WOLFSSL_ENTER("wolfSSL_BN_to_ASN1_INTEGER"); if (ai == NULL) { a = wolfSSL_ASN1_INTEGER_new(); if (a == NULL) return NULL; a->type = V_ASN1_INTEGER; } else { a = ai; } if (a) { if (wolfSSL_BN_is_negative(bn) && !wolfSSL_BN_is_zero(bn)) { a->type |= V_ASN1_NEG_INTEGER; a->negative = 1; } len = wolfSSL_BN_num_bytes(bn); if (len == 0) len = 1; /* allocate buffer */ if (len + extraTagSz > (int)sizeof(a->intData)) { /* create new data buffer and copy over */ a->data = (byte*)XMALLOC(len + extraTagSz, NULL, DYNAMIC_TYPE_OPENSSL); if (a->data == NULL) { if (a != ai) wolfSSL_ASN1_INTEGER_free(a); return NULL; } a->isDynamic = 1; } else { XMEMSET(a->intData, 0, sizeof(a->intData)); a->data = a->intData; a->isDynamic = 0; } /* populate data */ if (wolfSSL_BN_is_zero(bn)) { a->data[0] = 0; } else { len = wolfSSL_BN_bn2bin(bn, a->data); if (len < 0) { wolfSSL_ASN1_INTEGER_free(a); return NULL; } } a->length = len; /* Write ASN tag */ idx = SetASNInt(a->length, a->data[0], intTag); XMEMMOVE(a->data + idx, a->data, a->length); XMEMCPY(a->data, intTag, idx); a->dataMax = a->length += idx; } return a; } #ifdef OPENSSL_ALL void *wolfSSL_ASN1_item_new(const WOLFSSL_ASN1_ITEM *tpl) { void *ret = NULL; const WOLFSSL_ASN1_TEMPLATE *member = NULL; size_t i; WOLFSSL_ENTER("wolfSSL_ASN1_item_new"); if (!tpl) { return NULL; } if (!(ret = (void *)XMALLOC(tpl->size, NULL, DYNAMIC_TYPE_OPENSSL))) { return NULL; } XMEMSET(ret, 0, tpl->size); for (member = tpl->members, i = 0; i < tpl->mcount; member++, i++) { switch (member->type) { case WOLFSSL_X509_ALGOR_ASN1: { WOLFSSL_X509_ALGOR* algor = wolfSSL_X509_ALGOR_new(); if (!algor) { goto error; } *(WOLFSSL_X509_ALGOR**)(((byte*)ret) + member->offset) = algor; break; } case WOLFSSL_ASN1_BIT_STRING_ASN1: { WOLFSSL_ASN1_BIT_STRING* bit_str = wolfSSL_ASN1_BIT_STRING_new(); if (!bit_str) { goto error; } *(WOLFSSL_ASN1_BIT_STRING**)(((byte*)ret) + member->offset) = bit_str; break; } default: WOLFSSL_MSG("Type not supported in wolfSSL_ASN1_item_new"); goto error; } } return ret; error: wolfSSL_ASN1_item_free(ret, tpl); return NULL; } void wolfSSL_ASN1_item_free(void *val, const WOLFSSL_ASN1_ITEM *tpl) { const WOLFSSL_ASN1_TEMPLATE *member = NULL; size_t i; WOLFSSL_ENTER("wolfSSL_ASN1_item_free"); if (val) { for (member = tpl->members, i = 0; i < tpl->mcount; member++, i++) { switch (member->type) { case WOLFSSL_X509_ALGOR_ASN1: { WOLFSSL_X509_ALGOR* algor = *(WOLFSSL_X509_ALGOR**) (((byte*)val) + member->offset); if (algor) { wolfSSL_X509_ALGOR_free(algor); } break; } case WOLFSSL_ASN1_BIT_STRING_ASN1: { WOLFSSL_ASN1_BIT_STRING* bit_str = *(WOLFSSL_ASN1_BIT_STRING**) (((byte*)val) + member->offset); if (bit_str) { wolfSSL_ASN1_BIT_STRING_free(bit_str); } break; } default: WOLFSSL_MSG("Type not supported in wolfSSL_ASN1_item_free"); } } XFREE(val, NULL, DYNAMIC_TYPE_OPENSSL); } } #define bufLenOrNull(buf, len) ((buf) ? (buf) + (len) : NULL) static int i2dProcessMembers(const void *src, byte *buf, const WOLFSSL_ASN1_TEMPLATE *members, size_t mcount) { const WOLFSSL_ASN1_TEMPLATE *member = NULL; int len = 0, ret; size_t i; WOLFSSL_ENTER("processMembers"); for (member = members, i = 0; i < mcount; member++, i++) { switch (member->type) { case WOLFSSL_X509_ALGOR_ASN1: { word32 oid = 0; word32 idx = 0; const WOLFSSL_X509_ALGOR* algor = *(const WOLFSSL_X509_ALGOR**) (((byte*)src) + member->offset); if (!algor->algorithm) { WOLFSSL_LEAVE("processMembers", WOLFSSL_FAILURE); return WOLFSSL_FAILURE; } if (GetObjectId(algor->algorithm->obj, &idx, &oid, algor->algorithm->grp, algor->algorithm->objSz) < 0) { WOLFSSL_MSG("Issue getting OID of object"); return -1; } ret = SetAlgoID(oid, bufLenOrNull(buf, len), algor->algorithm->grp, 0); if (!ret) { return WOLFSSL_FAILURE; } len += ret; break; } case WOLFSSL_ASN1_BIT_STRING_ASN1: { const WOLFSSL_ASN1_BIT_STRING* bit_str; bit_str = *(const WOLFSSL_ASN1_BIT_STRING**) (((byte*)src) + member->offset); len += SetBitString(bit_str->length, 0, bufLenOrNull(buf, len)); if (buf && bit_str->data) { XMEMCPY(buf + len, bit_str->data, bit_str->length); } len += bit_str->length; break; } default: WOLFSSL_MSG("Type not support in processMembers"); WOLFSSL_LEAVE("processMembers", WOLFSSL_FAILURE); return WOLFSSL_FAILURE; } } WOLFSSL_LEAVE("processMembers", len); return len; } static int wolfSSL_ASN1_item_i2d_1(const void *src, byte *buf, const WOLFSSL_ASN1_ITEM *tpl, int *len) { *len = 0; switch (tpl->type) { case ASN_SEQUENCE: { int seq_len = i2dProcessMembers(src, NULL, tpl->members, tpl->mcount); if (seq_len == WOLFSSL_FAILURE) return WOLFSSL_FAILURE; *len += SetSequence(seq_len, bufLenOrNull(buf, *len)); if (buf) { if (i2dProcessMembers(src, bufLenOrNull(buf, *len), tpl->members, tpl->mcount) != seq_len) { WOLFSSL_MSG("Inconsistent sequence length"); return WOLFSSL_FAILURE; } } *len += seq_len; break; } default: WOLFSSL_MSG("Type not supported in wolfSSL_ASN1_item_i2d"); return WOLFSSL_FAILURE; } return WOLFSSL_SUCCESS; } int wolfSSL_ASN1_item_i2d(const void *src, byte **dest, const WOLFSSL_ASN1_ITEM *tpl) { int len; byte *buf = NULL; WOLFSSL_ENTER("wolfSSL_ASN1_item_i2d"); if ((src == NULL) || (tpl == NULL)) goto error; if (wolfSSL_ASN1_item_i2d_1(src, NULL, tpl, &len) != WOLFSSL_SUCCESS) goto error; if (dest == NULL) { WOLFSSL_LEAVE("wolfSSL_ASN1_item_i2d", WOLFSSL_SUCCESS); return len; } if (*dest == NULL) { buf = (byte*)XMALLOC(len, NULL, DYNAMIC_TYPE_ASN1); if (buf == NULL) goto error; } else buf = *dest; if (wolfSSL_ASN1_item_i2d_1(src, buf, tpl, &len) != WOLFSSL_SUCCESS) goto error; if (*dest == NULL) *dest = buf; else { /* XXX *dest length is not checked because the user is responsible * for providing a long enough buffer */ XMEMCPY(*dest, buf, len); } WOLFSSL_LEAVE("wolfSSL_ASN1_item_i2d", len); return len; error: if (buf) { XFREE(buf, NULL, DYNAMIC_TYPE_ASN1); } WOLFSSL_LEAVE("wolfSSL_ASN1_item_i2d", WOLFSSL_FAILURE); return WOLFSSL_FAILURE; } #endif /* OPENSSL_ALL */ #endif /* OPENSSL_EXTRA */ #ifdef OPENSSL_EXTRA WOLFSSL_HMAC_CTX* wolfSSL_HMAC_CTX_new(void) { WOLFSSL_HMAC_CTX* hmac_ctx = (WOLFSSL_HMAC_CTX*)XMALLOC( sizeof(WOLFSSL_HMAC_CTX), NULL, DYNAMIC_TYPE_OPENSSL); if (hmac_ctx != NULL) { XMEMSET(hmac_ctx, 0, sizeof(WOLFSSL_HMAC_CTX)); } return hmac_ctx; } int wolfSSL_HMAC_CTX_Init(WOLFSSL_HMAC_CTX* ctx) { WOLFSSL_MSG("wolfSSL_HMAC_CTX_Init"); if (ctx != NULL) { /* wc_HmacSetKey sets up ctx->hmac */ XMEMSET(ctx, 0, sizeof(WOLFSSL_HMAC_CTX)); } return WOLFSSL_SUCCESS; } int wolfSSL_HMAC_Init_ex(WOLFSSL_HMAC_CTX* ctx, const void* key, int keylen, const EVP_MD* type, WOLFSSL_ENGINE* e) { WOLFSSL_ENTER("wolfSSL_HMAC_Init_ex"); /* WOLFSSL_ENGINE not used, call wolfSSL_HMAC_Init */ (void)e; return wolfSSL_HMAC_Init(ctx, key, keylen, type); } /* helper function for Deep copy of internal wolfSSL hmac structure * returns WOLFSSL_SUCCESS on success */ int wolfSSL_HmacCopy(Hmac* des, Hmac* src) { void* heap; int ret; #ifndef HAVE_FIPS heap = src->heap; #else heap = NULL; #endif if (wc_HmacInit(des, heap, 0) != 0) { return WOLFSSL_FAILURE; } /* requires that hash structures have no dynamic parts to them */ switch (src->macType) { #ifndef NO_MD5 case WC_MD5: ret = wc_Md5Copy(&src->hash.md5, &des->hash.md5); break; #endif /* !NO_MD5 */ #ifndef NO_SHA case WC_SHA: ret = wc_ShaCopy(&src->hash.sha, &des->hash.sha); break; #endif /* !NO_SHA */ #ifdef WOLFSSL_SHA224 case WC_SHA224: ret = wc_Sha224Copy(&src->hash.sha224, &des->hash.sha224); break; #endif /* WOLFSSL_SHA224 */ #ifndef NO_SHA256 case WC_SHA256: ret = wc_Sha256Copy(&src->hash.sha256, &des->hash.sha256); break; #endif /* !NO_SHA256 */ #ifdef WOLFSSL_SHA384 case WC_SHA384: ret = wc_Sha384Copy(&src->hash.sha384, &des->hash.sha384); break; #endif /* WOLFSSL_SHA384 */ #ifdef WOLFSSL_SHA512 case WC_SHA512: ret = wc_Sha512Copy(&src->hash.sha512, &des->hash.sha512); break; #endif /* WOLFSSL_SHA512 */ #ifdef WOLFSSL_SHA3 #ifndef WOLFSSL_NOSHA3_224 case WC_SHA3_224: ret = wc_Sha3_224_Copy(&src->hash.sha3, &des->hash.sha3); break; #endif /* WOLFSSL_NO_SHA3_224 */ #ifndef WOLFSSL_NOSHA3_256 case WC_SHA3_256: ret = wc_Sha3_256_Copy(&src->hash.sha3, &des->hash.sha3); break; #endif /* WOLFSSL_NO_SHA3_256 */ #ifndef WOLFSSL_NOSHA3_384 case WC_SHA3_384: ret = wc_Sha3_384_Copy(&src->hash.sha3, &des->hash.sha3); break; #endif /* WOLFSSL_NO_SHA3_384 */ #ifndef WOLFSSL_NOSHA3_512 case WC_SHA3_512: ret = wc_Sha3_512_Copy(&src->hash.sha3, &des->hash.sha3); break; #endif /* WOLFSSL_NO_SHA3_512 */ #endif /* WOLFSSL_SHA3 */ default: return WOLFSSL_FAILURE; } if (ret != 0) return WOLFSSL_FAILURE; XMEMCPY((byte*)des->ipad, (byte*)src->ipad, WC_HMAC_BLOCK_SIZE); XMEMCPY((byte*)des->opad, (byte*)src->opad, WC_HMAC_BLOCK_SIZE); XMEMCPY((byte*)des->innerHash, (byte*)src->innerHash, WC_MAX_DIGEST_SIZE); #ifndef HAVE_FIPS des->heap = heap; #endif des->macType = src->macType; des->innerHashKeyed = src->innerHashKeyed; #ifdef WOLFSSL_ASYNC_CRYPT XMEMCPY(&des->asyncDev, &src->asyncDev, sizeof(WC_ASYNC_DEV)); des->keyLen = src->keyLen; #ifdef HAVE_CAVIUM des->data = (byte*)XMALLOC(src->dataLen, des->heap, DYNAMIC_TYPE_HMAC); if (des->data == NULL) { return BUFFER_E; } XMEMCPY(des->data, src->data, src->dataLen); des->dataLen = src->dataLen; #endif /* HAVE_CAVIUM */ #endif /* WOLFSSL_ASYNC_CRYPT */ return WOLFSSL_SUCCESS; } /* Deep copy of information from src to des structure * * des destination to copy information to * src structure to get information from * * Returns WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE on error */ int wolfSSL_HMAC_CTX_copy(WOLFSSL_HMAC_CTX* des, WOLFSSL_HMAC_CTX* src) { WOLFSSL_ENTER("wolfSSL_HMAC_CTX_copy"); if (des == NULL || src == NULL) { return WOLFSSL_FAILURE; } des->type = src->type; XMEMCPY((byte *)&des->save_ipad, (byte *)&src->hmac.ipad, WC_HMAC_BLOCK_SIZE); XMEMCPY((byte *)&des->save_opad, (byte *)&src->hmac.opad, WC_HMAC_BLOCK_SIZE); return wolfSSL_HmacCopy(&des->hmac, &src->hmac); } #if defined(HAVE_FIPS) && \ (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2)) static int _HMAC_Init(Hmac* hmac, int type, void* heap) { int ret = 0; switch (type) { #ifndef NO_MD5 case WC_MD5: ret = wc_InitMd5(&hmac->hash.md5); break; #endif /* !NO_MD5 */ #ifndef NO_SHA case WC_SHA: ret = wc_InitSha(&hmac->hash.sha); break; #endif /* !NO_SHA */ #ifdef WOLFSSL_SHA224 case WC_SHA224: ret = wc_InitSha224(&hmac->hash.sha224); break; #endif /* WOLFSSL_SHA224 */ #ifndef NO_SHA256 case WC_SHA256: ret = wc_InitSha256(&hmac->hash.sha256); break; #endif /* !NO_SHA256 */ #ifdef WOLFSSL_SHA384 case WC_SHA384: ret = wc_InitSha384(&hmac->hash.sha384); break; #endif /* WOLFSSL_SHA384 */ #ifdef WOLFSSL_SHA512 case WC_SHA512: ret = wc_InitSha512(&hmac->hash.sha512); break; #endif /* WOLFSSL_SHA512 */ #ifdef WOLFSSL_SHA3 case WC_SHA3_224: ret = wc_InitSha3_224(&hmac->hash.sha3, heap, INVALID_DEVID); break; case WC_SHA3_256: ret = wc_InitSha3_256(&hmac->hash.sha3, heap, INVALID_DEVID); break; case WC_SHA3_384: ret = wc_InitSha3_384(&hmac->hash.sha3, heap, INVALID_DEVID); break; case WC_SHA3_512: ret = wc_InitSha3_512(&hmac->hash.sha3, heap, INVALID_DEVID); break; #endif default: ret = BAD_FUNC_ARG; break; } (void)heap; return ret; } #else #define _HMAC_Init _InitHmac #endif int wolfSSL_HMAC_Init(WOLFSSL_HMAC_CTX* ctx, const void* key, int keylen, const EVP_MD* type) { int hmac_error = 0; void* heap = NULL; int inited; WOLFSSL_MSG("wolfSSL_HMAC_Init"); if (ctx == NULL) { WOLFSSL_MSG("no ctx on init"); return WOLFSSL_FAILURE; } #ifndef HAVE_FIPS heap = ctx->hmac.heap; #endif if (type) { WOLFSSL_MSG("init has type"); #ifndef NO_MD5 if (XSTRNCMP(type, "MD5", 3) == 0) { WOLFSSL_MSG("md5 hmac"); ctx->type = WC_MD5; } else #endif #ifdef WOLFSSL_SHA224 if (XSTRNCMP(type, "SHA224", 6) == 0) { WOLFSSL_MSG("sha224 hmac"); ctx->type = WC_SHA224; } else #endif #ifndef NO_SHA256 if (XSTRNCMP(type, "SHA256", 6) == 0) { WOLFSSL_MSG("sha256 hmac"); ctx->type = WC_SHA256; } else #endif #ifdef WOLFSSL_SHA384 if (XSTRNCMP(type, "SHA384", 6) == 0) { WOLFSSL_MSG("sha384 hmac"); ctx->type = WC_SHA384; } else #endif #ifdef WOLFSSL_SHA512 if (XSTRNCMP(type, "SHA512", 6) == 0) { WOLFSSL_MSG("sha512 hmac"); ctx->type = WC_SHA512; } else #endif #ifdef WOLFSSL_SHA3 #ifndef WOLFSSL_NOSHA3_224 if (XSTRNCMP(type, "SHA3_224", 8) == 0) { WOLFSSL_MSG("sha3_224 hmac"); ctx->type = WC_SHA3_224; } else #endif #ifndef WOLFSSL_NOSHA3_256 if (XSTRNCMP(type, "SHA3_256", 8) == 0) { WOLFSSL_MSG("sha3_256 hmac"); ctx->type = WC_SHA3_256; } else #endif if (XSTRNCMP(type, "SHA3_384", 8) == 0) { WOLFSSL_MSG("sha3_384 hmac"); ctx->type = WC_SHA3_384; } else #ifndef WOLFSSL_NOSHA3_512 if (XSTRNCMP(type, "SHA3_512", 8) == 0) { WOLFSSL_MSG("sha3_512 hmac"); ctx->type = WC_SHA3_512; } else #endif #endif #ifndef NO_SHA /* has to be last since would pick or 256, 384, or 512 too */ if (XSTRNCMP(type, "SHA", 3) == 0) { WOLFSSL_MSG("sha hmac"); ctx->type = WC_SHA; } else #endif { WOLFSSL_MSG("bad init type"); return WOLFSSL_FAILURE; } } /* Check if init has been called before */ inited = (ctx->hmac.macType != WC_HASH_TYPE_NONE); /* Free if needed */ if (inited) { wc_HmacFree(&ctx->hmac); } if (key != NULL) { WOLFSSL_MSG("keying hmac"); if (wc_HmacInit(&ctx->hmac, NULL, INVALID_DEVID) == 0) { hmac_error = wc_HmacSetKey(&ctx->hmac, ctx->type, (const byte*)key, (word32)keylen); if (hmac_error < 0){ /* in FIPS mode a key < 14 characters will fail here */ WOLFSSL_MSG("hmac set key error"); WOLFSSL_ERROR(hmac_error); wc_HmacFree(&ctx->hmac); return WOLFSSL_FAILURE; } XMEMCPY((byte *)&ctx->save_ipad, (byte *)&ctx->hmac.ipad, WC_HMAC_BLOCK_SIZE); XMEMCPY((byte *)&ctx->save_opad, (byte *)&ctx->hmac.opad, WC_HMAC_BLOCK_SIZE); } /* OpenSSL compat, no error */ } else if (!inited) { return WOLFSSL_FAILURE; } else if (ctx->type >= 0) { /* MD5 == 0 */ WOLFSSL_MSG("recover hmac"); if (wc_HmacInit(&ctx->hmac, NULL, INVALID_DEVID) == 0) { ctx->hmac.macType = (byte)ctx->type; ctx->hmac.innerHashKeyed = 0; XMEMCPY((byte *)&ctx->hmac.ipad, (byte *)&ctx->save_ipad, WC_HMAC_BLOCK_SIZE); XMEMCPY((byte *)&ctx->hmac.opad, (byte *)&ctx->save_opad, WC_HMAC_BLOCK_SIZE); if ((hmac_error = _HMAC_Init(&ctx->hmac, ctx->hmac.macType, heap)) !=0) { WOLFSSL_MSG("hmac init error"); WOLFSSL_ERROR(hmac_error); return WOLFSSL_FAILURE; } } } (void)hmac_error; return WOLFSSL_SUCCESS; } int wolfSSL_HMAC_Update(WOLFSSL_HMAC_CTX* ctx, const unsigned char* data, int len) { int hmac_error = 0; WOLFSSL_MSG("wolfSSL_HMAC_Update"); if (ctx == NULL) { WOLFSSL_MSG("no ctx"); return WOLFSSL_FAILURE; } if (data) { WOLFSSL_MSG("updating hmac"); hmac_error = wc_HmacUpdate(&ctx->hmac, data, (word32)len); if (hmac_error < 0){ WOLFSSL_MSG("hmac update error"); return WOLFSSL_FAILURE; } } return WOLFSSL_SUCCESS; } int wolfSSL_HMAC_Final(WOLFSSL_HMAC_CTX* ctx, unsigned char* hash, unsigned int* len) { int hmac_error; WOLFSSL_MSG("wolfSSL_HMAC_Final"); /* "len" parameter is optional. */ if (ctx == NULL || hash == NULL) { WOLFSSL_MSG("invalid parameter"); return WOLFSSL_FAILURE; } WOLFSSL_MSG("final hmac"); hmac_error = wc_HmacFinal(&ctx->hmac, hash); if (hmac_error < 0){ WOLFSSL_MSG("final hmac error"); return WOLFSSL_FAILURE; } if (len) { WOLFSSL_MSG("setting output len"); switch (ctx->type) { #ifndef NO_MD5 case WC_MD5: *len = WC_MD5_DIGEST_SIZE; break; #endif #ifndef NO_SHA case WC_SHA: *len = WC_SHA_DIGEST_SIZE; break; #endif #ifdef WOLFSSL_SHA224 case WC_SHA224: *len = WC_SHA224_DIGEST_SIZE; break; #endif #ifndef NO_SHA256 case WC_SHA256: *len = WC_SHA256_DIGEST_SIZE; break; #endif #ifdef WOLFSSL_SHA384 case WC_SHA384: *len = WC_SHA384_DIGEST_SIZE; break; #endif #ifdef WOLFSSL_SHA512 case WC_SHA512: *len = WC_SHA512_DIGEST_SIZE; break; #endif #ifdef WOLFSSL_SHA3 #ifndef WOLFSSL_NOSHA3_224 case WC_SHA3_224: *len = WC_SHA3_224_DIGEST_SIZE; break; #endif #ifndef WOLFSSL_NOSHA3_256 case WC_SHA3_256: *len = WC_SHA3_256_DIGEST_SIZE; break; #endif #ifndef WOLFSSL_NOSHA3_384 case WC_SHA3_384: *len = WC_SHA3_384_DIGEST_SIZE; break; #endif #ifndef WOLFSSL_NOSHA3_512 case WC_SHA3_512: *len = WC_SHA3_512_DIGEST_SIZE; break; #endif #endif default: WOLFSSL_MSG("bad hmac type"); return WOLFSSL_FAILURE; } } return WOLFSSL_SUCCESS; } int wolfSSL_HMAC_cleanup(WOLFSSL_HMAC_CTX* ctx) { WOLFSSL_MSG("wolfSSL_HMAC_cleanup"); if (ctx) { wc_HmacFree(&ctx->hmac); } return WOLFSSL_SUCCESS; } void wolfSSL_HMAC_CTX_cleanup(WOLFSSL_HMAC_CTX* ctx) { if (ctx) { wolfSSL_HMAC_cleanup(ctx); } } void wolfSSL_HMAC_CTX_free(WOLFSSL_HMAC_CTX* ctx) { if (ctx) { wolfSSL_HMAC_CTX_cleanup(ctx); XFREE(ctx, NULL, DYNAMIC_TYPE_OPENSSL); } } size_t wolfSSL_HMAC_size(const WOLFSSL_HMAC_CTX *ctx) { if (!ctx) { return 0; } return (size_t)wc_HashGetDigestSize((enum wc_HashType)ctx->hmac.macType); } const WOLFSSL_EVP_MD *wolfSSL_HMAC_CTX_get_md(const WOLFSSL_HMAC_CTX *ctx) { if (!ctx) { return NULL; } return wolfSSL_macType2EVP_md((enum wc_HashType)ctx->type); } #if defined(WOLFSSL_CMAC) && defined(OPENSSL_EXTRA) && \ defined(WOLFSSL_AES_DIRECT) WOLFSSL_CMAC_CTX* wolfSSL_CMAC_CTX_new(void) { WOLFSSL_CMAC_CTX* ctx = NULL; ctx = (WOLFSSL_CMAC_CTX*)XMALLOC(sizeof(WOLFSSL_CMAC_CTX), NULL, DYNAMIC_TYPE_OPENSSL); if (ctx != NULL) { ctx->internal = (Cmac*)XMALLOC(sizeof(Cmac), NULL, DYNAMIC_TYPE_CMAC); if (ctx->internal == NULL) { XFREE(ctx, NULL, DYNAMIC_TYPE_OPENSSL); ctx = NULL; } } if (ctx != NULL) { ctx->cctx = wolfSSL_EVP_CIPHER_CTX_new(); if (ctx->cctx == NULL) { XFREE(ctx->internal, NULL, DYNAMIC_TYPE_CMAC); XFREE(ctx, NULL, DYNAMIC_TYPE_OPENSSL); ctx = NULL; } } return ctx; } void wolfSSL_CMAC_CTX_free(WOLFSSL_CMAC_CTX *ctx) { if (ctx != NULL) { if (ctx->internal != NULL) { XFREE(ctx->internal, NULL, DYNAMIC_TYPE_CMAC); } if (ctx->cctx != NULL) { wolfSSL_EVP_CIPHER_CTX_free(ctx->cctx); } XFREE(ctx, NULL, DYNAMIC_TYPE_OPENSSL); } } WOLFSSL_EVP_CIPHER_CTX* wolfSSL_CMAC_CTX_get0_cipher_ctx(WOLFSSL_CMAC_CTX* ctx) { WOLFSSL_EVP_CIPHER_CTX* cctx = NULL; if (ctx != NULL) { cctx = ctx->cctx; } return cctx; } int wolfSSL_CMAC_Init(WOLFSSL_CMAC_CTX* ctx, const void *key, size_t keyLen, const WOLFSSL_EVP_CIPHER* cipher, WOLFSSL_ENGINE* engine) { int ret = WOLFSSL_SUCCESS; (void)engine; WOLFSSL_ENTER("wolfSSL_CMAC_Init"); if (ctx == NULL || cipher == NULL || ( cipher != EVP_AES_128_CBC && cipher != EVP_AES_192_CBC && cipher != EVP_AES_256_CBC)) { ret = WOLFSSL_FAILURE; } if (ret == WOLFSSL_SUCCESS) { ret = wc_InitCmac((Cmac*)ctx->internal, (const byte*)key, (word32)keyLen, WC_CMAC_AES, NULL); if (ret != 0) { ret = WOLFSSL_FAILURE; } else { ret = WOLFSSL_SUCCESS; } } if (ret == WOLFSSL_SUCCESS) { ret = wolfSSL_EVP_CipherInit(ctx->cctx, cipher, (const byte*)key, NULL, 1); } WOLFSSL_LEAVE("wolfSSL_CMAC_Init", ret); return ret; } int wolfSSL_CMAC_Update(WOLFSSL_CMAC_CTX* ctx, const void* data, size_t len) { int ret = WOLFSSL_SUCCESS; WOLFSSL_ENTER("wolfSSL_CMAC_Update"); if (ctx == NULL || ctx->internal == NULL) { ret = WOLFSSL_FAILURE; } if (ret == WOLFSSL_SUCCESS) { if (data) { ret = wc_CmacUpdate((Cmac*)ctx->internal, (const byte*)data, (word32)len); if (ret != 0){ ret = WOLFSSL_FAILURE; } else { ret = WOLFSSL_SUCCESS; } } } WOLFSSL_LEAVE("wolfSSL_CMAC_Update", ret); return ret; } int wolfSSL_CMAC_Final(WOLFSSL_CMAC_CTX* ctx, unsigned char* out, size_t* len) { int ret = WOLFSSL_SUCCESS; int blockSize; WOLFSSL_ENTER("wolfSSL_CMAC_Final"); if (ctx == NULL || ctx->cctx == NULL || ctx->internal == NULL || len == NULL) { ret = WOLFSSL_FAILURE; } if (ret == WOLFSSL_SUCCESS) { blockSize = EVP_CIPHER_CTX_block_size(ctx->cctx); if (blockSize <= 0) { ret = WOLFSSL_FAILURE; } else { *len = blockSize; } } if (ret == WOLFSSL_SUCCESS) { word32 len32 = (word32)*len; ret = wc_CmacFinal((Cmac*)ctx->internal, out, &len32); *len = (size_t)len32; if (ret != 0) { ret = WOLFSSL_FAILURE; } else { ret = WOLFSSL_SUCCESS; } } WOLFSSL_LEAVE("wolfSSL_CMAC_Final", ret); return ret; } #endif /* WOLFSSL_CMAC && OPENSSL_EXTRA && WOLFSSL_AES_DIRECT */ #endif /* OPENSSL_EXTRA */ #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) /* Free the dynamically allocated data. * * p Pointer to dynamically allocated memory. */ void wolfSSL_OPENSSL_free(void* p) { WOLFSSL_MSG("wolfSSL_OPENSSL_free"); XFREE(p, NULL, DYNAMIC_TYPE_OPENSSL); } #endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ #ifdef OPENSSL_EXTRA void *wolfSSL_OPENSSL_malloc(size_t a) { return (void *)XMALLOC(a, NULL, DYNAMIC_TYPE_OPENSSL); } int wolfSSL_OPENSSL_hexchar2int(unsigned char c) { /* 'char' is unsigned on some platforms. */ return (int)(signed char)HexCharToByte((char)c); } unsigned char *wolfSSL_OPENSSL_hexstr2buf(const char *str, long *len) { unsigned char* targetBuf; int srcDigitHigh = 0; int srcDigitLow = 0; size_t srcLen; size_t srcIdx = 0; long targetIdx = 0; srcLen = XSTRLEN(str); targetBuf = (unsigned char*)XMALLOC(srcLen / 2, NULL, DYNAMIC_TYPE_OPENSSL); if (targetBuf == NULL) { return NULL; } while (srcIdx < srcLen) { if (str[srcIdx] == ':') { srcIdx++; continue; } srcDigitHigh = wolfSSL_OPENSSL_hexchar2int(str[srcIdx++]); srcDigitLow = wolfSSL_OPENSSL_hexchar2int(str[srcIdx++]); if (srcDigitHigh < 0 || srcDigitLow < 0) { WOLFSSL_MSG("Invalid hex character."); XFREE(targetBuf, NULL, DYNAMIC_TYPE_OPENSSL); return NULL; } targetBuf[targetIdx++] = (unsigned char)((srcDigitHigh << 4) | srcDigitLow); } if (len != NULL) *len = targetIdx; return targetBuf; } int wolfSSL_OPENSSL_init_ssl(word64 opts, const OPENSSL_INIT_SETTINGS *settings) { (void)opts; (void)settings; return wolfSSL_library_init(); } int wolfSSL_OPENSSL_init_crypto(word64 opts, const OPENSSL_INIT_SETTINGS* settings) { (void)opts; (void)settings; return wolfSSL_library_init(); } #if defined(WOLFSSL_KEY_GEN) && defined(WOLFSSL_PEM_TO_DER) int EncryptDerKey(byte *der, int *derSz, const EVP_CIPHER* cipher, unsigned char* passwd, int passwdSz, byte **cipherInfo, int maxDerSz) { int ret, paddingSz; word32 idx, cipherInfoSz; #ifdef WOLFSSL_SMALL_STACK EncryptedInfo* info = NULL; #else EncryptedInfo info[1]; #endif WOLFSSL_ENTER("EncryptDerKey"); if (der == NULL || derSz == NULL || cipher == NULL || passwd == NULL || cipherInfo == NULL) return BAD_FUNC_ARG; #ifdef WOLFSSL_SMALL_STACK info = (EncryptedInfo*)XMALLOC(sizeof(EncryptedInfo), NULL, DYNAMIC_TYPE_ENCRYPTEDINFO); if (info == NULL) { WOLFSSL_MSG("malloc failed"); return WOLFSSL_FAILURE; } #endif XMEMSET(info, 0, sizeof(EncryptedInfo)); /* set the cipher name on info */ XSTRNCPY(info->name, cipher, NAME_SZ-1); info->name[NAME_SZ-1] = '\0'; /* null term */ ret = wc_EncryptedInfoGet(info, info->name); if (ret != 0) { WOLFSSL_MSG("unsupported cipher"); #ifdef WOLFSSL_SMALL_STACK XFREE(info, NULL, DYNAMIC_TYPE_ENCRYPTEDINFO); #endif return WOLFSSL_FAILURE; } /* Generate a random salt */ if (wolfSSL_RAND_bytes(info->iv, info->ivSz) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("generate iv failed"); #ifdef WOLFSSL_SMALL_STACK XFREE(info, NULL, DYNAMIC_TYPE_ENCRYPTEDINFO); #endif return WOLFSSL_FAILURE; } /* add the padding before encryption */ paddingSz = ((*derSz)/info->ivSz + 1) * info->ivSz - (*derSz); if (paddingSz == 0) paddingSz = info->ivSz; if (maxDerSz < *derSz + paddingSz) { WOLFSSL_MSG("not enough DER buffer allocated"); #ifdef WOLFSSL_SMALL_STACK XFREE(info, NULL, DYNAMIC_TYPE_ENCRYPTEDINFO); #endif return WOLFSSL_FAILURE; } XMEMSET(der+(*derSz), (byte)paddingSz, paddingSz); (*derSz) += paddingSz; /* encrypt buffer */ if (wc_BufferKeyEncrypt(info, der, *derSz, passwd, passwdSz, WC_MD5) != 0) { WOLFSSL_MSG("encrypt key failed"); #ifdef WOLFSSL_SMALL_STACK XFREE(info, NULL, DYNAMIC_TYPE_ENCRYPTEDINFO); #endif return WOLFSSL_FAILURE; } /* create cipher info : 'cipher_name,Salt(hex)' */ cipherInfoSz = (word32)(2*info->ivSz + XSTRLEN(info->name) + 2); *cipherInfo = (byte*)XMALLOC(cipherInfoSz, NULL, DYNAMIC_TYPE_STRING); if (*cipherInfo == NULL) { WOLFSSL_MSG("malloc failed"); #ifdef WOLFSSL_SMALL_STACK XFREE(info, NULL, DYNAMIC_TYPE_ENCRYPTEDINFO); #endif return WOLFSSL_FAILURE; } XSTRLCPY((char*)*cipherInfo, info->name, cipherInfoSz); XSTRLCAT((char*)*cipherInfo, ",", cipherInfoSz); idx = (word32)XSTRLEN((char*)*cipherInfo); cipherInfoSz -= idx; ret = Base16_Encode(info->iv, info->ivSz, *cipherInfo+idx, &cipherInfoSz); #ifdef WOLFSSL_SMALL_STACK XFREE(info, NULL, DYNAMIC_TYPE_ENCRYPTEDINFO); #endif if (ret != 0) { WOLFSSL_MSG("Base16_Encode failed"); XFREE(*cipherInfo, NULL, DYNAMIC_TYPE_STRING); return WOLFSSL_FAILURE; } return WOLFSSL_SUCCESS; } #endif /* WOLFSSL_KEY_GEN || WOLFSSL_PEM_TO_DER */ #ifndef NO_BIO static int pem_write_bio_pubkey(WOLFSSL_BIO* bio, WOLFSSL_EVP_PKEY* key) { int ret; int pemSz; byte* pemBuf; int derSz = 0; byte* derBuf = NULL; if (bio == NULL || key == NULL) { WOLFSSL_MSG("Bad parameters"); return WOLFSSL_FAILURE; } switch (key->type) { #if defined(WOLFSSL_KEY_GEN) && !defined(NO_RSA) && !defined(HAVE_USER_RSA) case EVP_PKEY_RSA: if ((derSz = wolfSSL_RSA_To_Der(key->rsa, &derBuf, 1, bio->heap)) < 0) { WOLFSSL_MSG("wolfSSL_RSA_To_Der failed"); break; } break; #endif /* WOLFSSL_KEY_GEN && !NO_RSA && !HAVE_USER_RSA */ #if !defined(NO_DSA) && !defined(HAVE_SELFTEST) && (defined(WOLFSSL_KEY_GEN) || \ defined(WOLFSSL_CERT_GEN)) case EVP_PKEY_DSA: if (key->dsa == NULL) { WOLFSSL_MSG("key->dsa is null"); break; } derSz = MAX_DSA_PUBKEY_SZ; derBuf = (byte*)XMALLOC(derSz, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); if (derBuf == NULL) { WOLFSSL_MSG("malloc failed"); break; } /* Key to DER */ derSz = wc_DsaKeyToPublicDer((DsaKey*)key->dsa->internal, derBuf, derSz); if (derSz < 0) { WOLFSSL_MSG("wc_DsaKeyToDer failed"); break; } break; #endif /* !NO_DSA && !HAVE_SELFTEST && (WOLFSSL_KEY_GEN || WOLFSSL_CERT_GEN) */ #if defined(HAVE_ECC) && defined(HAVE_ECC_KEY_EXPORT) case EVP_PKEY_EC: { if (key->ecc == NULL) { WOLFSSL_MSG("key->ecc is null"); break; } derSz = wc_EccPublicKeyDerSize((ecc_key*)key->ecc->internal, 1); if (derSz <= 0) { WOLFSSL_MSG("wc_EccPublicKeyDerSize failed"); break; } derBuf = (byte*)XMALLOC(derSz, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); if (derBuf == NULL) { WOLFSSL_MSG("malloc failed"); break; } derSz = wc_EccPublicKeyToDer((ecc_key*)key->ecc->internal, derBuf, derSz, 1); if (derSz < 0) { WOLFSSL_MSG("wc_EccPublicKeyToDer failed"); break; } break; } #endif /* HAVE_ECC && HAVE_ECC_KEY_EXPORT */ #if !defined(NO_DH) && (defined(WOLFSSL_QT) || defined(OPENSSL_ALL)) case EVP_PKEY_DH: WOLFSSL_MSG("Writing DH PUBKEY not supported!"); break; #endif /* !NO_DH && (WOLFSSL_QT || OPENSSL_ALL) */ default: WOLFSSL_MSG("Unknown Key type!"); break; } if (derBuf == NULL || derSz <= 0) { if (derBuf != NULL) XFREE(derBuf, bio->heap, DYNAMIC_TYPE_DER); return WOLFSSL_FAILURE; } pemSz = wc_DerToPem(derBuf, derSz, NULL, 0, PUBLICKEY_TYPE); if (pemSz < 0) { WOLFSSL_LEAVE("pem_write_bio_pubkey", pemSz); XFREE(derBuf, bio->heap, DYNAMIC_TYPE_DER); return WOLFSSL_FAILURE; } pemBuf = (byte*)XMALLOC(pemSz, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); if (pemBuf == NULL) { WOLFSSL_LEAVE("pem_write_bio_pubkey", pemSz); XFREE(derBuf, bio->heap, DYNAMIC_TYPE_DER); return WOLFSSL_FAILURE; } ret = wc_DerToPem(derBuf, derSz, pemBuf, pemSz, PUBLICKEY_TYPE); XFREE(derBuf, bio->heap, DYNAMIC_TYPE_DER); if (ret < 0) { WOLFSSL_LEAVE("pem_write_bio_pubkey", ret); XFREE(pemBuf, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); return WOLFSSL_FAILURE; } ret = wolfSSL_BIO_write(bio, pemBuf, pemSz); XFREE(pemBuf, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); if (ret != pemSz) { WOLFSSL_MSG("Unable to write full PEM to BIO"); return WOLFSSL_FAILURE; } return WOLFSSL_SUCCESS; } /* Takes a public key and writes it out to a WOLFSSL_BIO * Returns WOLFSSL_SUCCESS or WOLFSSL_FAILURE */ int wolfSSL_PEM_write_bio_PUBKEY(WOLFSSL_BIO* bio, WOLFSSL_EVP_PKEY* key) { WOLFSSL_ENTER("wolfSSL_PEM_write_bio_PUBKEY"); return pem_write_bio_pubkey(bio, key); } /* Takes a private key and writes it out to a WOLFSSL_BIO * Returns WOLFSSL_SUCCESS or WOLFSSL_FAILURE */ int wolfSSL_PEM_write_bio_PrivateKey(WOLFSSL_BIO* bio, WOLFSSL_EVP_PKEY* key, const WOLFSSL_EVP_CIPHER* cipher, unsigned char* passwd, int len, wc_pem_password_cb* cb, void* arg) { byte* keyDer; int pemSz; int type; int ret; byte* tmp; (void)cipher; (void)passwd; (void)len; (void)cb; (void)arg; WOLFSSL_ENTER("wolfSSL_PEM_write_bio_PrivateKey"); if (bio == NULL || key == NULL) { WOLFSSL_MSG("Bad Function Arguments"); return WOLFSSL_FAILURE; } keyDer = (byte*)key->pkey.ptr; switch (key->type) { #ifndef NO_RSA case EVP_PKEY_RSA: type = PRIVATEKEY_TYPE; break; #endif #ifndef NO_DSA case EVP_PKEY_DSA: type = DSA_PRIVATEKEY_TYPE; break; #endif #ifdef HAVE_ECC case EVP_PKEY_EC: type = ECC_PRIVATEKEY_TYPE; break; #endif #if !defined(NO_DH) && (defined(WOLFSSL_QT) || defined(OPENSSL_ALL)) case EVP_PKEY_DH: type = DH_PRIVATEKEY_TYPE; break; #endif default: WOLFSSL_MSG("Unknown Key type!"); type = PRIVATEKEY_TYPE; } pemSz = wc_DerToPem(keyDer, key->pkey_sz, NULL, 0, type); if (pemSz < 0) { WOLFSSL_LEAVE("wolfSSL_PEM_write_bio_PrivateKey", pemSz); return WOLFSSL_FAILURE; } tmp = (byte*)XMALLOC(pemSz, bio->heap, DYNAMIC_TYPE_OPENSSL); if (tmp == NULL) { return MEMORY_E; } ret = wc_DerToPem(keyDer, key->pkey_sz, tmp, pemSz, type); if (ret < 0) { WOLFSSL_LEAVE("wolfSSL_PEM_write_bio_PrivateKey", ret); XFREE(tmp, bio->heap, DYNAMIC_TYPE_OPENSSL); return WOLFSSL_FAILURE; } ret = wolfSSL_BIO_write(bio, tmp, pemSz); XFREE(tmp, bio->heap, DYNAMIC_TYPE_OPENSSL); if (ret != pemSz) { WOLFSSL_MSG("Unable to write full PEM to BIO"); return WOLFSSL_FAILURE; } return WOLFSSL_SUCCESS; } #endif /* !NO_BIO */ /* Colon separated list of + algorithms. * Replaces list in context. */ int wolfSSL_CTX_set1_sigalgs_list(WOLFSSL_CTX* ctx, const char* list) { WOLFSSL_MSG("wolfSSL_CTX_set1_sigalg_list"); if (ctx == NULL || list == NULL) { WOLFSSL_MSG("Bad function arguments"); return WOLFSSL_FAILURE; } /* alloc/init on demand only */ if (ctx->suites == NULL) { ctx->suites = (Suites*)XMALLOC(sizeof(Suites), ctx->heap, DYNAMIC_TYPE_SUITES); if (ctx->suites == NULL) { WOLFSSL_MSG("Memory alloc for Suites failed"); return WOLFSSL_FAILURE; } XMEMSET(ctx->suites, 0, sizeof(Suites)); } return SetSuitesHashSigAlgo(ctx->suites, list); } /* Colon separated list of + algorithms. * Replaces list in SSL. */ int wolfSSL_set1_sigalgs_list(WOLFSSL* ssl, const char* list) { WOLFSSL_MSG("wolfSSL_set1_sigalg_list"); if (ssl == NULL) { WOLFSSL_MSG("Bad function arguments"); return WOLFSSL_FAILURE; } #ifdef SINGLE_THREADED if (ssl->ctx->suites == ssl->suites) { ssl->suites = (Suites*)XMALLOC(sizeof(Suites), ssl->heap, DYNAMIC_TYPE_SUITES); if (ssl->suites == NULL) { WOLFSSL_MSG("Suites Memory error"); return MEMORY_E; } *ssl->suites = *ssl->ctx->suites; ssl->options.ownSuites = 1; } #endif if (ssl == NULL || list == NULL) { WOLFSSL_MSG("Bad function arguments"); return WOLFSSL_FAILURE; } return SetSuitesHashSigAlgo(ssl->suites, list); } struct WOLFSSL_HashSigInfo { int hashAlgo; int sigAlgo; int nid; } wolfssl_hash_sig_info[] = { #ifndef NO_RSA #ifndef NO_SHA256 { sha256_mac, rsa_sa_algo, CTC_SHA256wRSA }, #endif #ifdef WOLFSSL_SHA384 { sha384_mac, rsa_sa_algo, CTC_SHA384wRSA }, #endif #ifdef WOLFSSL_SHA512 { sha512_mac, rsa_sa_algo, CTC_SHA512wRSA }, #endif #ifdef WOLFSSL_SHA224 { sha224_mac, rsa_sa_algo, CTC_SHA224wRSA }, #endif #ifndef NO_SHA { sha_mac, rsa_sa_algo, CTC_SHAwRSA }, #endif #ifdef WC_RSA_PSS #ifndef NO_SHA256 { sha256_mac, rsa_pss_sa_algo, CTC_SHA256wRSA }, #endif #ifdef WOLFSSL_SHA384 { sha384_mac, rsa_pss_sa_algo, CTC_SHA384wRSA }, #endif #ifdef WOLFSSL_SHA512 { sha512_mac, rsa_pss_sa_algo, CTC_SHA512wRSA }, #endif #ifdef WOLFSSL_SHA224 { sha224_mac, rsa_pss_sa_algo, CTC_SHA224wRSA }, #endif #endif #endif #ifdef HAVE_ECC #ifndef NO_SHA256 { sha256_mac, ecc_dsa_sa_algo, CTC_SHA256wECDSA }, #endif #ifdef WOLFSSL_SHA384 { sha384_mac, ecc_dsa_sa_algo, CTC_SHA384wECDSA }, #endif #ifdef WOLFSSL_SHA512 { sha512_mac, ecc_dsa_sa_algo, CTC_SHA512wECDSA }, #endif #ifdef WOLFSSL_SHA224 { sha224_mac, ecc_dsa_sa_algo, CTC_SHA224wECDSA }, #endif #ifndef NO_SHA { sha_mac, ecc_dsa_sa_algo, CTC_SHAwECDSA }, #endif #endif #ifdef HAVE_ED25519 { no_mac, ed25519_sa_algo, CTC_ED25519 }, #endif #ifdef HAVE_ED448 { no_mac, ed448_sa_algo, CTC_ED448 }, #endif #ifdef HAVE_PQC { no_mac, falcon_level1_sa_algo, CTC_FALCON_LEVEL1 }, { no_mac, falcon_level5_sa_algo, CTC_FALCON_LEVEL5 }, #endif #ifndef NO_DSA #ifndef NO_SHA { sha_mac, dsa_sa_algo, CTC_SHAwDSA }, #endif #endif }; #define WOLFSSL_HASH_SIG_INFO_SZ \ (int)(sizeof(wolfssl_hash_sig_info)/sizeof(*wolfssl_hash_sig_info)) int wolfSSL_get_signature_nid(WOLFSSL *ssl, int* nid) { int i; int ret = WOLFSSL_FAILURE; WOLFSSL_MSG("wolfSSL_get_signature_nid"); if (ssl == NULL) { WOLFSSL_MSG("Bad function arguments"); return WOLFSSL_FAILURE; } for (i = 0; i < WOLFSSL_HASH_SIG_INFO_SZ; i++) { if (ssl->suites->hashAlgo == wolfssl_hash_sig_info[i].hashAlgo && ssl->suites->sigAlgo == wolfssl_hash_sig_info[i].sigAlgo) { *nid = wolfssl_hash_sig_info[i].nid; ret = WOLFSSL_SUCCESS; break; } } return ret; } #ifdef HAVE_ECC #if defined(WOLFSSL_TLS13) && defined(HAVE_SUPPORTED_CURVES) static int populate_groups(int* groups, int max_count, char *list) { char *end; int len; int count = 0; const WOLF_EC_NIST_NAME* nist_name; if (!groups || !list) { return -1; } for (end = list; ; list = ++end) { if (count > max_count) { WOLFSSL_MSG("Too many curves in list"); return -1; } while (*end != ':' && *end != '\0') end++; len = (int)(end - list); /* end points to char after end * of curve name so no need for -1 */ if ((len < kNistCurves_MIN_NAME_LEN) || (len > kNistCurves_MAX_NAME_LEN)) { WOLFSSL_MSG("Unrecognized curve name in list"); return -1; } for (nist_name = kNistCurves; nist_name->name != NULL; nist_name++) { if (len == nist_name->name_len && XSTRNCMP(list, nist_name->name, nist_name->name_len) == 0) { break; } } if (!nist_name->name) { WOLFSSL_MSG("Unrecognized curve name in list"); return -1; } groups[count++] = nist_name->nid; if (*end == '\0') break; } return count; } int wolfSSL_CTX_set1_groups_list(WOLFSSL_CTX *ctx, char *list) { int groups[WOLFSSL_MAX_GROUP_COUNT]; int count; if (!ctx || !list) { return WOLFSSL_FAILURE; } if ((count = populate_groups(groups, WOLFSSL_MAX_GROUP_COUNT, list)) == -1) { return WOLFSSL_FAILURE; } return wolfSSL_CTX_set1_groups(ctx, groups, count); } int wolfSSL_set1_groups_list(WOLFSSL *ssl, char *list) { int groups[WOLFSSL_MAX_GROUP_COUNT]; int count; if (!ssl || !list) { return WOLFSSL_FAILURE; } if ((count = populate_groups(groups, WOLFSSL_MAX_GROUP_COUNT, list)) == -1) { return WOLFSSL_FAILURE; } return wolfSSL_set1_groups(ssl, groups, count); } #endif /* WOLFSSL_TLS13 */ #endif /* HAVE_ECC */ #ifndef NO_BIO /* Number of bytes to read from a file at a time. */ #define PEM_READ_FILE_CHUNK_SZ 100 static int pem_read_bio_file(WOLFSSL_BIO* bio, char** pem) { int ret = 0; int idx = 0; int sz = PEM_READ_FILE_CHUNK_SZ; /* read from file by chunks */ int memSz = 0; char* mem = NULL; char* tmp; /* Allocate a chunk to read into. */ tmp = (char*)XMALLOC(sz, bio->heap, DYNAMIC_TYPE_OPENSSL); if (tmp == NULL) { WOLFSSL_MSG("Memory error"); ret = MEMORY_E; } while (ret == 0 && (sz = wolfSSL_BIO_read(bio, tmp, sz)) > 0) { char* newMem; /* sanity check for signed overflow */ if (memSz + sz < 0) { break; } /* Reallocate to make space for read data. */ newMem = (char*)XREALLOC(mem, memSz + sz, bio->heap, DYNAMIC_TYPE_OPENSSL); if (newMem == NULL) { WOLFSSL_MSG("Memory error"); ret = MEMORY_E; break; } mem = newMem; /* Copy in new data. */ XMEMCPY(mem + idx, tmp, sz); memSz += sz; idx += sz; sz = PEM_READ_FILE_CHUNK_SZ; /* read another chunk from file */ } XFREE(tmp, bio->heap, DYNAMIC_TYPE_OPENSSL); tmp = NULL; if (ret == 0) { /* Check data was read. */ if (memSz <= 0) { WOLFSSL_MSG("No data to read from bio"); ret = BUFFER_E; } else { /* Return size of data read. */ ret = memSz; } } /* Dispose of any allocated memory on error. */ if (ret < 0) { XFREE(mem, bio->heap, DYNAMIC_TYPE_OPENSSL); mem = NULL; } *pem = mem; return ret; } static int pem_read_bio_pending(WOLFSSL_BIO* bio, int pendingSz, char** pem) { int ret = 0; char* mem; /* Allocate buffer to hold pending data. */ mem = (char*)XMALLOC(pendingSz, bio->heap, DYNAMIC_TYPE_OPENSSL); if (mem == NULL) { WOLFSSL_MSG("Memory error"); ret = MEMORY_E; } else if ((ret = wolfSSL_BIO_read(bio, mem, pendingSz)) <= 0) { /* Pending data not read. */ XFREE(mem, bio->heap, DYNAMIC_TYPE_OPENSSL); mem = NULL; ret = MEMORY_E; } *pem = mem; return ret; } static int pem_read_bio_key(WOLFSSL_BIO* bio, wc_pem_password_cb* cb, void* pass, int keyType, int* eccFlag, DerBuffer** der) { #ifdef WOLFSSL_SMALL_STACK EncryptedInfo* info = NULL; #else EncryptedInfo info[1]; #endif /* WOLFSSL_SMALL_STACK */ wc_pem_password_cb* localCb = NULL; char* mem = NULL; int ret; if (cb != NULL) { localCb = cb; } else if (pass != NULL) { localCb = wolfSSL_PEM_def_callback; } if ((ret = wolfSSL_BIO_pending(bio)) > 0) { ret = pem_read_bio_pending(bio, ret, &mem); } else if (bio->type == WOLFSSL_BIO_FILE) { ret = pem_read_bio_file(bio, &mem); } else { WOLFSSL_MSG("No data to read from bio"); ret = NOT_COMPILED_IN; } #ifdef WOLFSSL_SMALL_STACK if (ret >= 0) { info = (EncryptedInfo*)XMALLOC(sizeof(EncryptedInfo), NULL, DYNAMIC_TYPE_TMP_BUFFER); if (info == NULL) { WOLFSSL_MSG("Error getting memory for EncryptedInfo structure"); XFREE(mem, bio->heap, DYNAMIC_TYPE_OPENSSL); mem = NULL; ret = MEMORY_E; } } #endif /* WOLFSSL_SMALL_STACK */ if (ret >= 0) { int memSz = ret; XMEMSET(info, 0, sizeof(EncryptedInfo)); info->passwd_cb = localCb; info->passwd_userdata = pass; /* Do not strip PKCS8 header */ ret = PemToDer((const unsigned char*)mem, memSz, keyType, der, NULL, info, eccFlag); if (ret < 0) { WOLFSSL_MSG("Bad PEM To DER"); } /* Write left over data back to BIO if not a file BIO */ else if ((memSz - (int)info->consumed) > 0 && bio->type != WOLFSSL_BIO_FILE) { if (wolfSSL_BIO_write(bio, mem + (int)info->consumed, memSz - (int)info->consumed) <= 0) { WOLFSSL_MSG("Unable to advance bio read pointer"); } } } #ifdef WOLFSSL_SMALL_STACK XFREE(info, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif XFREE(mem, bio->heap, DYNAMIC_TYPE_OPENSSL); return ret; } WOLFSSL_EVP_PKEY* wolfSSL_PEM_read_bio_PrivateKey(WOLFSSL_BIO* bio, WOLFSSL_EVP_PKEY** key, wc_pem_password_cb* cb, void* pass) { WOLFSSL_EVP_PKEY* pkey = NULL; DerBuffer* der = NULL; int keyFormat = 0; int type = -1; WOLFSSL_ENTER("wolfSSL_PEM_read_bio_PrivateKey"); if (bio == NULL) return pkey; if (pem_read_bio_key(bio, cb, pass, PRIVATEKEY_TYPE, &keyFormat, &der) >= 0) { const unsigned char* ptr = der->buffer; if (keyFormat) { /* keyFormat is Key_Sum enum */ if (keyFormat == RSAk) type = EVP_PKEY_RSA; else if (keyFormat == ECDSAk) type = EVP_PKEY_EC; else if (keyFormat == DSAk) type = EVP_PKEY_DSA; else if (keyFormat == DHk) type = EVP_PKEY_DH; } else { /* Default to RSA if format is not set */ type = EVP_PKEY_RSA; } /* handle case where reuse is attempted */ if (key != NULL && *key != NULL) pkey = *key; wolfSSL_d2i_PrivateKey(type, &pkey, &ptr, der->length); if (pkey == NULL) { WOLFSSL_MSG("Error loading DER buffer into WOLFSSL_EVP_PKEY"); } } FreeDer(&der); if (key != NULL && pkey != NULL) *key = pkey; WOLFSSL_LEAVE("wolfSSL_PEM_read_bio_PrivateKey", 0); return pkey; } WOLFSSL_EVP_PKEY *wolfSSL_PEM_read_bio_PUBKEY(WOLFSSL_BIO* bio, WOLFSSL_EVP_PKEY **key, wc_pem_password_cb *cb, void *pass) { WOLFSSL_EVP_PKEY* pkey = NULL; DerBuffer* der = NULL; int keyFormat = 0; WOLFSSL_ENTER("wolfSSL_PEM_read_bio_PUBKEY"); if (bio == NULL) return pkey; if (pem_read_bio_key(bio, cb, pass, PUBLICKEY_TYPE, &keyFormat, &der) >= 0) { const unsigned char* ptr = der->buffer; /* handle case where reuse is attempted */ if (key != NULL && *key != NULL) pkey = *key; wolfSSL_d2i_PUBKEY(&pkey, &ptr, der->length); if (pkey == NULL) { WOLFSSL_MSG("Error loading DER buffer into WOLFSSL_EVP_PKEY"); } } FreeDer(&der); if (key != NULL && pkey != NULL) *key = pkey; WOLFSSL_LEAVE("wolfSSL_PEM_read_bio_PUBKEY", 0); return pkey; } #endif /* !NO_BIO */ #if !defined(NO_FILESYSTEM) WOLFSSL_EVP_PKEY *wolfSSL_PEM_read_PUBKEY(XFILE fp, WOLFSSL_EVP_PKEY **x, wc_pem_password_cb *cb, void *u) { (void)fp; (void)x; (void)cb; (void)u; WOLFSSL_MSG("wolfSSL_PEM_read_PUBKEY not implemented"); return NULL; } #endif /* NO_FILESYSTEM */ #endif /* OPENSSL_EXTRA */ #ifdef WOLFSSL_ALT_CERT_CHAINS int wolfSSL_is_peer_alt_cert_chain(const WOLFSSL* ssl) { int isUsing = 0; if (ssl) isUsing = ssl->options.usingAltCertChain; return isUsing; } #endif /* WOLFSSL_ALT_CERT_CHAINS */ #ifdef SESSION_CERTS #ifdef WOLFSSL_ALT_CERT_CHAINS /* Get peer's alternate certificate chain */ WOLFSSL_X509_CHAIN* wolfSSL_get_peer_alt_chain(WOLFSSL* ssl) { WOLFSSL_ENTER("wolfSSL_get_peer_alt_chain"); if (ssl) return &ssl->session->altChain; return 0; } #endif /* WOLFSSL_ALT_CERT_CHAINS */ /* Get peer's certificate chain */ WOLFSSL_X509_CHAIN* wolfSSL_get_peer_chain(WOLFSSL* ssl) { WOLFSSL_ENTER("wolfSSL_get_peer_chain"); if (ssl) return &ssl->session->chain; return 0; } /* Get peer's certificate chain total count */ int wolfSSL_get_chain_count(WOLFSSL_X509_CHAIN* chain) { WOLFSSL_ENTER("wolfSSL_get_chain_count"); if (chain) return chain->count; return 0; } /* Get peer's ASN.1 DER certificate at index (idx) length in bytes */ int wolfSSL_get_chain_length(WOLFSSL_X509_CHAIN* chain, int idx) { WOLFSSL_ENTER("wolfSSL_get_chain_length"); if (chain) return chain->certs[idx].length; return 0; } /* Get peer's ASN.1 DER certificate at index (idx) */ byte* wolfSSL_get_chain_cert(WOLFSSL_X509_CHAIN* chain, int idx) { WOLFSSL_ENTER("wolfSSL_get_chain_cert"); if (chain) return chain->certs[idx].buffer; return 0; } /* Get peer's wolfSSL X509 certificate at index (idx) */ WOLFSSL_X509* wolfSSL_get_chain_X509(WOLFSSL_X509_CHAIN* chain, int idx) { int ret; WOLFSSL_X509* x509 = NULL; #ifdef WOLFSSL_SMALL_STACK DecodedCert* cert = NULL; #else DecodedCert cert[1]; #endif WOLFSSL_ENTER("wolfSSL_get_chain_X509"); if (chain != NULL) { #ifdef WOLFSSL_SMALL_STACK cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, DYNAMIC_TYPE_DCERT); if (cert != NULL) #endif { InitDecodedCert(cert, chain->certs[idx].buffer, chain->certs[idx].length, NULL); if ((ret = ParseCertRelative(cert, CERT_TYPE, 0, NULL)) != 0) { WOLFSSL_MSG("Failed to parse cert"); } else { x509 = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), NULL, DYNAMIC_TYPE_X509); if (x509 == NULL) { WOLFSSL_MSG("Failed alloc X509"); } else { InitX509(x509, 1, NULL); if ((ret = CopyDecodedToX509(x509, cert)) != 0) { WOLFSSL_MSG("Failed to copy decoded"); wolfSSL_X509_free(x509); x509 = NULL; } } } FreeDecodedCert(cert); #ifdef WOLFSSL_SMALL_STACK XFREE(cert, NULL, DYNAMIC_TYPE_DCERT); #endif } } (void)ret; return x509; } /* Get peer's PEM certificate at index (idx), output to buffer if inLen big enough else return error (-1). If buffer is NULL only calculate outLen. Output length is in *outLen WOLFSSL_SUCCESS on ok */ int wolfSSL_get_chain_cert_pem(WOLFSSL_X509_CHAIN* chain, int idx, unsigned char* buf, int inLen, int* outLen) { #if defined(WOLFSSL_PEM_TO_DER) || defined(WOLFSSL_DER_TO_PEM) const char* header = NULL; const char* footer = NULL; int headerLen; int footerLen; int i; int err; word32 szNeeded = 0; WOLFSSL_ENTER("wolfSSL_get_chain_cert_pem"); if (!chain || !outLen || idx < 0 || idx >= wolfSSL_get_chain_count(chain)) return BAD_FUNC_ARG; err = wc_PemGetHeaderFooter(CERT_TYPE, &header, &footer); if (err != 0) return err; headerLen = (int)XSTRLEN(header); footerLen = (int)XSTRLEN(footer); /* Null output buffer return size needed in outLen */ if(!buf) { if(Base64_Encode(chain->certs[idx].buffer, chain->certs[idx].length, NULL, &szNeeded) != LENGTH_ONLY_E) return WOLFSSL_FAILURE; *outLen = szNeeded + headerLen + footerLen; return LENGTH_ONLY_E; } /* don't even try if inLen too short */ if (inLen < headerLen + footerLen + chain->certs[idx].length) return BAD_FUNC_ARG; /* header */ if (XMEMCPY(buf, header, headerLen) == NULL) return WOLFSSL_FATAL_ERROR; i = headerLen; /* body */ *outLen = inLen; /* input to Base64_Encode */ if ( (err = Base64_Encode(chain->certs[idx].buffer, chain->certs[idx].length, buf + i, (word32*)outLen)) < 0) return err; i += *outLen; /* footer */ if ( (i + footerLen) > inLen) return BAD_FUNC_ARG; if (XMEMCPY(buf + i, footer, footerLen) == NULL) return WOLFSSL_FATAL_ERROR; *outLen += headerLen + footerLen; return WOLFSSL_SUCCESS; #else (void)chain; (void)idx; (void)buf; (void)inLen; (void)outLen; return WOLFSSL_FAILURE; #endif /* WOLFSSL_PEM_TO_DER || WOLFSSL_DER_TO_PEM */ } /* get session ID */ WOLFSSL_ABI const byte* wolfSSL_get_sessionID(const WOLFSSL_SESSION* session) { WOLFSSL_ENTER("wolfSSL_get_sessionID"); session = ClientSessionToSession(session); if (session) return session->sessionID; return NULL; } #endif /* SESSION_CERTS */ #ifdef HAVE_FUZZER void wolfSSL_SetFuzzerCb(WOLFSSL* ssl, CallbackFuzzer cbf, void* fCtx) { if (ssl) { ssl->fuzzerCb = cbf; ssl->fuzzerCtx = fCtx; } } #endif #ifndef NO_CERTS #ifdef HAVE_PK_CALLBACKS #ifdef HAVE_ECC void wolfSSL_CTX_SetEccKeyGenCb(WOLFSSL_CTX* ctx, CallbackEccKeyGen cb) { if (ctx) ctx->EccKeyGenCb = cb; } void wolfSSL_SetEccKeyGenCtx(WOLFSSL* ssl, void *ctx) { if (ssl) ssl->EccKeyGenCtx = ctx; } void* wolfSSL_GetEccKeyGenCtx(WOLFSSL* ssl) { if (ssl) return ssl->EccKeyGenCtx; return NULL; } void wolfSSL_CTX_SetEccSignCtx(WOLFSSL_CTX* ctx, void *userCtx) { if (ctx) ctx->EccSignCtx = userCtx; } void* wolfSSL_CTX_GetEccSignCtx(WOLFSSL_CTX* ctx) { if (ctx) return ctx->EccSignCtx; return NULL; } WOLFSSL_ABI void wolfSSL_CTX_SetEccSignCb(WOLFSSL_CTX* ctx, CallbackEccSign cb) { if (ctx) ctx->EccSignCb = cb; } void wolfSSL_SetEccSignCtx(WOLFSSL* ssl, void *ctx) { if (ssl) ssl->EccSignCtx = ctx; } void* wolfSSL_GetEccSignCtx(WOLFSSL* ssl) { if (ssl) return ssl->EccSignCtx; return NULL; } void wolfSSL_CTX_SetEccVerifyCb(WOLFSSL_CTX* ctx, CallbackEccVerify cb) { if (ctx) ctx->EccVerifyCb = cb; } void wolfSSL_SetEccVerifyCtx(WOLFSSL* ssl, void *ctx) { if (ssl) ssl->EccVerifyCtx = ctx; } void* wolfSSL_GetEccVerifyCtx(WOLFSSL* ssl) { if (ssl) return ssl->EccVerifyCtx; return NULL; } void wolfSSL_CTX_SetEccSharedSecretCb(WOLFSSL_CTX* ctx, CallbackEccSharedSecret cb) { if (ctx) ctx->EccSharedSecretCb = cb; } void wolfSSL_SetEccSharedSecretCtx(WOLFSSL* ssl, void *ctx) { if (ssl) ssl->EccSharedSecretCtx = ctx; } void* wolfSSL_GetEccSharedSecretCtx(WOLFSSL* ssl) { if (ssl) return ssl->EccSharedSecretCtx; return NULL; } #endif /* HAVE_ECC */ #ifdef HAVE_ED25519 void wolfSSL_CTX_SetEd25519SignCb(WOLFSSL_CTX* ctx, CallbackEd25519Sign cb) { if (ctx) ctx->Ed25519SignCb = cb; } void wolfSSL_SetEd25519SignCtx(WOLFSSL* ssl, void *ctx) { if (ssl) ssl->Ed25519SignCtx = ctx; } void* wolfSSL_GetEd25519SignCtx(WOLFSSL* ssl) { if (ssl) return ssl->Ed25519SignCtx; return NULL; } void wolfSSL_CTX_SetEd25519VerifyCb(WOLFSSL_CTX* ctx, CallbackEd25519Verify cb) { if (ctx) ctx->Ed25519VerifyCb = cb; } void wolfSSL_SetEd25519VerifyCtx(WOLFSSL* ssl, void *ctx) { if (ssl) ssl->Ed25519VerifyCtx = ctx; } void* wolfSSL_GetEd25519VerifyCtx(WOLFSSL* ssl) { if (ssl) return ssl->Ed25519VerifyCtx; return NULL; } #endif /* HAVE_ED25519 */ #ifdef HAVE_CURVE25519 void wolfSSL_CTX_SetX25519KeyGenCb(WOLFSSL_CTX* ctx, CallbackX25519KeyGen cb) { if (ctx) ctx->X25519KeyGenCb = cb; } void wolfSSL_SetX25519KeyGenCtx(WOLFSSL* ssl, void *ctx) { if (ssl) ssl->X25519KeyGenCtx = ctx; } void* wolfSSL_GetX25519KeyGenCtx(WOLFSSL* ssl) { if (ssl) return ssl->X25519KeyGenCtx; return NULL; } void wolfSSL_CTX_SetX25519SharedSecretCb(WOLFSSL_CTX* ctx, CallbackX25519SharedSecret cb) { if (ctx) ctx->X25519SharedSecretCb = cb; } void wolfSSL_SetX25519SharedSecretCtx(WOLFSSL* ssl, void *ctx) { if (ssl) ssl->X25519SharedSecretCtx = ctx; } void* wolfSSL_GetX25519SharedSecretCtx(WOLFSSL* ssl) { if (ssl) return ssl->X25519SharedSecretCtx; return NULL; } #endif /* HAVE_CURVE25519 */ #ifdef HAVE_ED448 void wolfSSL_CTX_SetEd448SignCb(WOLFSSL_CTX* ctx, CallbackEd448Sign cb) { if (ctx) ctx->Ed448SignCb = cb; } void wolfSSL_SetEd448SignCtx(WOLFSSL* ssl, void *ctx) { if (ssl) ssl->Ed448SignCtx = ctx; } void* wolfSSL_GetEd448SignCtx(WOLFSSL* ssl) { if (ssl) return ssl->Ed448SignCtx; return NULL; } void wolfSSL_CTX_SetEd448VerifyCb(WOLFSSL_CTX* ctx, CallbackEd448Verify cb) { if (ctx) ctx->Ed448VerifyCb = cb; } void wolfSSL_SetEd448VerifyCtx(WOLFSSL* ssl, void *ctx) { if (ssl) ssl->Ed448VerifyCtx = ctx; } void* wolfSSL_GetEd448VerifyCtx(WOLFSSL* ssl) { if (ssl) return ssl->Ed448VerifyCtx; return NULL; } #endif /* HAVE_ED448 */ #ifdef HAVE_CURVE448 void wolfSSL_CTX_SetX448KeyGenCb(WOLFSSL_CTX* ctx, CallbackX448KeyGen cb) { if (ctx) ctx->X448KeyGenCb = cb; } void wolfSSL_SetX448KeyGenCtx(WOLFSSL* ssl, void *ctx) { if (ssl) ssl->X448KeyGenCtx = ctx; } void* wolfSSL_GetX448KeyGenCtx(WOLFSSL* ssl) { if (ssl) return ssl->X448KeyGenCtx; return NULL; } void wolfSSL_CTX_SetX448SharedSecretCb(WOLFSSL_CTX* ctx, CallbackX448SharedSecret cb) { if (ctx) ctx->X448SharedSecretCb = cb; } void wolfSSL_SetX448SharedSecretCtx(WOLFSSL* ssl, void *ctx) { if (ssl) ssl->X448SharedSecretCtx = ctx; } void* wolfSSL_GetX448SharedSecretCtx(WOLFSSL* ssl) { if (ssl) return ssl->X448SharedSecretCtx; return NULL; } #endif /* HAVE_CURVE448 */ #ifndef NO_RSA void wolfSSL_CTX_SetRsaSignCb(WOLFSSL_CTX* ctx, CallbackRsaSign cb) { if (ctx) ctx->RsaSignCb = cb; } void wolfSSL_CTX_SetRsaSignCheckCb(WOLFSSL_CTX* ctx, CallbackRsaVerify cb) { if (ctx) ctx->RsaSignCheckCb = cb; } void wolfSSL_SetRsaSignCtx(WOLFSSL* ssl, void *ctx) { if (ssl) ssl->RsaSignCtx = ctx; } void* wolfSSL_GetRsaSignCtx(WOLFSSL* ssl) { if (ssl) return ssl->RsaSignCtx; return NULL; } void wolfSSL_CTX_SetRsaVerifyCb(WOLFSSL_CTX* ctx, CallbackRsaVerify cb) { if (ctx) ctx->RsaVerifyCb = cb; } void wolfSSL_SetRsaVerifyCtx(WOLFSSL* ssl, void *ctx) { if (ssl) ssl->RsaVerifyCtx = ctx; } void* wolfSSL_GetRsaVerifyCtx(WOLFSSL* ssl) { if (ssl) return ssl->RsaVerifyCtx; return NULL; } #ifdef WC_RSA_PSS void wolfSSL_CTX_SetRsaPssSignCb(WOLFSSL_CTX* ctx, CallbackRsaPssSign cb) { if (ctx) ctx->RsaPssSignCb = cb; } void wolfSSL_CTX_SetRsaPssSignCheckCb(WOLFSSL_CTX* ctx, CallbackRsaPssVerify cb) { if (ctx) ctx->RsaPssSignCheckCb = cb; } void wolfSSL_SetRsaPssSignCtx(WOLFSSL* ssl, void *ctx) { if (ssl) ssl->RsaPssSignCtx = ctx; } void* wolfSSL_GetRsaPssSignCtx(WOLFSSL* ssl) { if (ssl) return ssl->RsaPssSignCtx; return NULL; } void wolfSSL_CTX_SetRsaPssVerifyCb(WOLFSSL_CTX* ctx, CallbackRsaPssVerify cb) { if (ctx) ctx->RsaPssVerifyCb = cb; } void wolfSSL_SetRsaPssVerifyCtx(WOLFSSL* ssl, void *ctx) { if (ssl) ssl->RsaPssVerifyCtx = ctx; } void* wolfSSL_GetRsaPssVerifyCtx(WOLFSSL* ssl) { if (ssl) return ssl->RsaPssVerifyCtx; return NULL; } #endif /* WC_RSA_PSS */ void wolfSSL_CTX_SetRsaEncCb(WOLFSSL_CTX* ctx, CallbackRsaEnc cb) { if (ctx) ctx->RsaEncCb = cb; } void wolfSSL_SetRsaEncCtx(WOLFSSL* ssl, void *ctx) { if (ssl) ssl->RsaEncCtx = ctx; } void* wolfSSL_GetRsaEncCtx(WOLFSSL* ssl) { if (ssl) return ssl->RsaEncCtx; return NULL; } void wolfSSL_CTX_SetRsaDecCb(WOLFSSL_CTX* ctx, CallbackRsaDec cb) { if (ctx) ctx->RsaDecCb = cb; } void wolfSSL_SetRsaDecCtx(WOLFSSL* ssl, void *ctx) { if (ssl) ssl->RsaDecCtx = ctx; } void* wolfSSL_GetRsaDecCtx(WOLFSSL* ssl) { if (ssl) return ssl->RsaDecCtx; return NULL; } #endif /* NO_RSA */ /* callback for premaster secret generation */ void wolfSSL_CTX_SetGenPreMasterCb(WOLFSSL_CTX* ctx, CallbackGenPreMaster cb) { if (ctx) ctx->GenPreMasterCb = cb; } /* Set premaster secret generation callback context */ void wolfSSL_SetGenPreMasterCtx(WOLFSSL* ssl, void *ctx) { if (ssl) ssl->GenPreMasterCtx = ctx; } /* Get premaster secret generation callback context */ void* wolfSSL_GetGenPreMasterCtx(WOLFSSL* ssl) { if (ssl) return ssl->GenPreMasterCtx; return NULL; } /* callback for master secret generation */ void wolfSSL_CTX_SetGenMasterSecretCb(WOLFSSL_CTX* ctx, CallbackGenMasterSecret cb) { if (ctx) ctx->GenMasterCb = cb; } /* Set master secret generation callback context */ void wolfSSL_SetGenMasterSecretCtx(WOLFSSL* ssl, void *ctx) { if (ssl) ssl->GenMasterCtx = ctx; } /* Get master secret generation callback context */ void* wolfSSL_GetGenMasterSecretCtx(WOLFSSL* ssl) { if (ssl) return ssl->GenMasterCtx; return NULL; } /* callback for session key generation */ void wolfSSL_CTX_SetGenSessionKeyCb(WOLFSSL_CTX* ctx, CallbackGenSessionKey cb) { if (ctx) ctx->GenSessionKeyCb = cb; } /* Set session key generation callback context */ void wolfSSL_SetGenSessionKeyCtx(WOLFSSL* ssl, void *ctx) { if (ssl) ssl->GenSessionKeyCtx = ctx; } /* Get session key generation callback context */ void* wolfSSL_GetGenSessionKeyCtx(WOLFSSL* ssl) { if (ssl) return ssl->GenSessionKeyCtx; return NULL; } /* callback for setting encryption keys */ void wolfSSL_CTX_SetEncryptKeysCb(WOLFSSL_CTX* ctx, CallbackEncryptKeys cb) { if (ctx) ctx->EncryptKeysCb = cb; } /* Set encryption keys callback context */ void wolfSSL_SetEncryptKeysCtx(WOLFSSL* ssl, void *ctx) { if (ssl) ssl->EncryptKeysCtx = ctx; } /* Get encryption keys callback context */ void* wolfSSL_GetEncryptKeysCtx(WOLFSSL* ssl) { if (ssl) return ssl->EncryptKeysCtx; return NULL; } /* callback for Tls finished */ /* the callback can be used to build TLS Finished message if enabled */ void wolfSSL_CTX_SetTlsFinishedCb(WOLFSSL_CTX* ctx, CallbackTlsFinished cb) { if (ctx) ctx->TlsFinishedCb = cb; } /* Set Tls finished callback context */ void wolfSSL_SetTlsFinishedCtx(WOLFSSL* ssl, void *ctx) { if (ssl) ssl->TlsFinishedCtx = ctx; } /* Get Tls finished callback context */ void* wolfSSL_GetTlsFinishedCtx(WOLFSSL* ssl) { if (ssl) return ssl->TlsFinishedCtx; return NULL; } #if !defined(WOLFSSL_NO_TLS12) && !defined(WOLFSSL_AEAD_ONLY) /* callback for verify data */ void wolfSSL_CTX_SetVerifyMacCb(WOLFSSL_CTX* ctx, CallbackVerifyMac cb) { if (ctx) ctx->VerifyMacCb = cb; } /* Set set keys callback context */ void wolfSSL_SetVerifyMacCtx(WOLFSSL* ssl, void *ctx) { if (ssl) ssl->VerifyMacCtx = ctx; } /* Get set keys callback context */ void* wolfSSL_GetVerifyMacCtx(WOLFSSL* ssl) { if (ssl) return ssl->VerifyMacCtx; return NULL; } #endif /* !WOLFSSL_NO_TLS12 && !WOLFSSL_AEAD_ONLY */ #endif /* HAVE_PK_CALLBACKS */ #endif /* NO_CERTS */ #if defined(HAVE_PK_CALLBACKS) && !defined(NO_DH) void wolfSSL_CTX_SetDhAgreeCb(WOLFSSL_CTX* ctx, CallbackDhAgree cb) { if (ctx) ctx->DhAgreeCb = cb; } void wolfSSL_SetDhAgreeCtx(WOLFSSL* ssl, void *ctx) { if (ssl) ssl->DhAgreeCtx = ctx; } void* wolfSSL_GetDhAgreeCtx(WOLFSSL* ssl) { if (ssl) return ssl->DhAgreeCtx; return NULL; } #endif /* HAVE_PK_CALLBACKS && !NO_DH */ #if defined(HAVE_PK_CALLBACKS) && defined(HAVE_HKDF) void wolfSSL_CTX_SetHKDFExtractCb(WOLFSSL_CTX* ctx, CallbackHKDFExtract cb) { if (ctx) ctx->HkdfExtractCb = cb; } void wolfSSL_SetHKDFExtractCtx(WOLFSSL* ssl, void *ctx) { if (ssl) ssl->HkdfExtractCtx = ctx; } void* wolfSSL_GetHKDFExtractCtx(WOLFSSL* ssl) { if (ssl) return ssl->HkdfExtractCtx; return NULL; } #endif /* HAVE_PK_CALLBACKS && HAVE_HKDF */ #ifdef WOLFSSL_HAVE_WOLFSCEP /* Used by autoconf to see if wolfSCEP is available */ void wolfSSL_wolfSCEP(void) {} #endif #ifdef WOLFSSL_HAVE_CERT_SERVICE /* Used by autoconf to see if cert service is available */ void wolfSSL_cert_service(void) {} #endif #if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && \ !defined(WOLFCRYPT_ONLY) #ifndef NO_CERTS #if defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) /* Convert ASN1 input string into canonical ASN1 string */ /* , which has the following rules: */ /* convert to UTF8 */ /* convert to lower case */ /* multi-spaces collapsed */ /* @param asn_out a pointer to ASN1_STRING to be converted */ /* @param asn_in a pointer to input ASN1_STRING */ /* @return WOLFSSL_SUCCESS on successful converted, otherwise <=0 error code*/ int wolfSSL_ASN1_STRING_canon(WOLFSSL_ASN1_STRING* asn_out, const WOLFSSL_ASN1_STRING* asn_in) { char* dst; char* src; int i, len; WOLFSSL_ENTER("wolfSSL_ASN1_STRING_canon"); /* sanity check */ if (asn_out == NULL || asn_in == NULL) { WOLFSSL_MSG("invalid function arguments"); return BAD_FUNC_ARG; } switch (asn_in->type) { case MBSTRING_UTF8: case V_ASN1_PRINTABLESTRING: break; default: WOLFSSL_MSG("just copy string"); return wolfSSL_ASN1_STRING_copy(asn_out, asn_in); } /* type is set as UTF8 */ asn_out->type = MBSTRING_UTF8; asn_out->length = wolfSSL_ASN1_STRING_to_UTF8( (unsigned char**)&asn_out->data, (WOLFSSL_ASN1_STRING*)asn_in); if (asn_out->length < 0) { return WOLFSSL_FAILURE; } /* point to the last */ dst = asn_out->data + asn_out->length; /* point to the start */ src = asn_out->data; len = asn_out->length; /* trimming spaces at the head and tail */ dst--; for (; (len > 0 && XISSPACE(*dst)); len--) { dst--; } for (; (len > 0 && XISSPACE(*src)); len--) { src++; } /* point to the start */ dst = asn_out->data; for (i = 0; i < len; dst++, i++) { if (!XISASCII(*src)) { /* keep non-ascii code */ *dst = *src++; } else if (XISSPACE(*src)) { *dst = 0x20; /* space */ /* remove the rest of spaces */ while (XISSPACE(*++src) && i++ < len); } else { *dst = (char)XTOLOWER((unsigned char)*src++); } } /* put actual length */ asn_out->length = (int)(dst - asn_out->data); return WOLFSSL_SUCCESS; } #if defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) #if !defined(NO_FILESYSTEM) #ifndef NO_BIO WOLFSSL_EVP_PKEY* wolfSSL_PEM_read_PrivateKey(XFILE fp, WOLFSSL_EVP_PKEY **x, wc_pem_password_cb *cb, void *u) { int err = 0; WOLFSSL_EVP_PKEY* ret = NULL; WOLFSSL_BIO* bio = NULL; WOLFSSL_ENTER("wolfSSL_PEM_read_PrivateKey"); if (fp == XBADFILE) { err = 1; } if (err == 0) { bio = wolfSSL_BIO_new(wolfSSL_BIO_s_file()); err = bio == NULL; } if (err == 0) { err = wolfSSL_BIO_set_fp(bio, fp, BIO_NOCLOSE) != WOLFSSL_SUCCESS; } if (err == 0) { ret = wolfSSL_PEM_read_bio_PrivateKey(bio, x, cb, u); } if (bio != NULL) { wolfSSL_BIO_free(bio); } return ret; } #endif #endif #endif #endif /* OPENSSL_ALL || OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL*/ #if defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) #define PEM_BEGIN "-----BEGIN " #define PEM_BEGIN_SZ 11 #define PEM_END "-----END " #define PEM_END_SZ 9 #define PEM_HDR_FIN "-----" #define PEM_HDR_FIN_SZ 5 #define PEM_HDR_FIN_EOL_NEWLINE "-----\n" #define PEM_HDR_FIN_EOL_NULL_TERM "-----\0" #define PEM_HDR_FIN_EOL_SZ 6 #ifndef NO_BIO int wolfSSL_PEM_read_bio(WOLFSSL_BIO* bio, char **name, char **header, unsigned char **data, long *len) { int ret = WOLFSSL_SUCCESS; char pem[256]; int pemLen; char* p; char* nameStr = NULL; int nameLen = 0; char* headerStr = NULL; int headerLen; int headerFound = 0; unsigned char* der = NULL; word32 derLen = 0; if (bio == NULL || name == NULL || header == NULL || data == NULL || len == NULL) { return WOLFSSL_FAILURE; } /* Find header line. */ pem[sizeof(pem) - 1] = '\0'; while ((pemLen = wolfSSL_BIO_gets(bio, pem, sizeof(pem) - 1)) > 0) { if (XSTRNCMP(pem, PEM_BEGIN, PEM_BEGIN_SZ) == 0) break; } if (pemLen <= 0) ret = WOLFSSL_FAILURE; /* Have a header line. */ if (ret == WOLFSSL_SUCCESS) { while (pem[pemLen - 1] == '\r' || pem[pemLen - 1] == '\n') pemLen--; pem[pemLen] = '\0'; if (XSTRNCMP(pem + pemLen - PEM_HDR_FIN_SZ, PEM_HDR_FIN, PEM_HDR_FIN_SZ) != 0) { ret = WOLFSSL_FAILURE; } } /* Get out name. */ if (ret == WOLFSSL_SUCCESS) { nameLen = pemLen - PEM_BEGIN_SZ - PEM_HDR_FIN_SZ; nameStr = (char*)XMALLOC(nameLen + 1, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (nameStr == NULL) ret = WOLFSSL_FAILURE; } if (ret == WOLFSSL_SUCCESS) { XSTRNCPY(nameStr, pem + PEM_BEGIN_SZ, nameLen); nameStr[nameLen] = '\0'; /* Get header of PEM - encryption header. */ headerLen = 0; while ((pemLen = wolfSSL_BIO_gets(bio, pem, sizeof(pem) - 1)) > 0) { while (pemLen > 0 && (pem[pemLen - 1] == '\r' || pem[pemLen - 1] == '\n')) { pemLen--; } pem[pemLen++] = '\n'; pem[pemLen] = '\0'; /* Header separator is a blank line. */ if (pem[0] == '\n') { headerFound = 1; break; } /* Didn't find a blank line - no header. */ if (XSTRNCMP(pem, PEM_END, PEM_END_SZ) == 0) { der = (unsigned char*)headerStr; derLen = headerLen; /* Empty header - empty string. */ headerStr = (char*)XMALLOC(1, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (headerStr == NULL) ret = WOLFSSL_FAILURE; else headerStr[0] = '\0'; break; } p = (char*)XREALLOC(headerStr, headerLen + pemLen + 1, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (p == NULL) { ret = WOLFSSL_FAILURE; break; } headerStr = p; XMEMCPY(headerStr + headerLen, pem, pemLen + 1); headerLen += pemLen; } if (pemLen <= 0) ret = WOLFSSL_FAILURE; } /* Get body of PEM - if there was a header */ if (ret == WOLFSSL_SUCCESS && headerFound) { derLen = 0; while ((pemLen = wolfSSL_BIO_gets(bio, pem, sizeof(pem) - 1)) > 0) { while (pemLen > 0 && (pem[pemLen - 1] == '\r' || pem[pemLen - 1] == '\n')) { pemLen--; } pem[pemLen++] = '\n'; pem[pemLen] = '\0'; if (XSTRNCMP(pem, PEM_END, PEM_END_SZ) == 0) break; p = (char*)XREALLOC(der, derLen + pemLen + 1, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (p == NULL) { ret = WOLFSSL_FAILURE; break; } der = (unsigned char*)p; XMEMCPY(der + derLen, pem, pemLen + 1); derLen += pemLen; } if (pemLen <= 0) ret = WOLFSSL_FAILURE; } /* Check trailer. */ if (ret == WOLFSSL_SUCCESS) { if (XSTRNCMP(pem + PEM_END_SZ, nameStr, nameLen) != 0) ret = WOLFSSL_FAILURE; } if (ret == WOLFSSL_SUCCESS) { if (XSTRNCMP(pem + PEM_END_SZ + nameLen, PEM_HDR_FIN_EOL_NEWLINE, PEM_HDR_FIN_EOL_SZ) != 0 && XSTRNCMP(pem + PEM_END_SZ + nameLen, PEM_HDR_FIN_EOL_NULL_TERM, PEM_HDR_FIN_EOL_SZ) != 0) { ret = WOLFSSL_FAILURE; } } /* Base64 decode body. */ if (ret == WOLFSSL_SUCCESS) { if (Base64_Decode(der, derLen, der, &derLen) != 0) ret = WOLFSSL_FAILURE; } if (ret == WOLFSSL_SUCCESS) { *name = nameStr; *header = headerStr; *data = der; *len = derLen; nameStr = NULL; headerStr = NULL; der = NULL; } if (nameStr != NULL) XFREE(nameStr, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (headerStr != NULL) XFREE(headerStr, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (der != NULL) XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER); return ret; } int wolfSSL_PEM_write_bio(WOLFSSL_BIO* bio, const char *name, const char *header, const unsigned char *data, long len) { int err = 0; int outSz = 0; int nameLen; int headerLen; byte* pem = NULL; word32 pemLen; word32 derLen = (word32)len; if (bio == NULL || name == NULL || header == NULL || data == NULL) return 0; nameLen = (int)XSTRLEN(name); headerLen = (int)XSTRLEN(header); pemLen = (derLen + 2) / 3 * 4; pemLen += (pemLen + 63) / 64; pem = (byte*)XMALLOC(pemLen, NULL, DYNAMIC_TYPE_TMP_BUFFER); err = pem == NULL; if (!err) err = Base64_Encode(data, derLen, pem, &pemLen) != 0; if (!err) { err = wolfSSL_BIO_write(bio, PEM_BEGIN, PEM_BEGIN_SZ) != (int)PEM_BEGIN_SZ; } if (!err) err = wolfSSL_BIO_write(bio, name, nameLen) != nameLen; if (!err) { err = wolfSSL_BIO_write(bio, PEM_HDR_FIN_EOL_NEWLINE, PEM_HDR_FIN_EOL_SZ) != (int)PEM_HDR_FIN_EOL_SZ; } if (!err && headerLen > 0) { err = wolfSSL_BIO_write(bio, header, headerLen) != headerLen; /* Blank line after a header and before body. */ if (!err) err = wolfSSL_BIO_write(bio, "\n", 1) != 1; headerLen++; } if (!err) err = wolfSSL_BIO_write(bio, pem, pemLen) != (int)pemLen; if (!err) err = wolfSSL_BIO_write(bio, PEM_END, PEM_END_SZ) != (int)PEM_END_SZ; if (!err) err = wolfSSL_BIO_write(bio, name, nameLen) != nameLen; if (!err) { err = wolfSSL_BIO_write(bio, PEM_HDR_FIN_EOL_NEWLINE, PEM_HDR_FIN_EOL_SZ) != (int)PEM_HDR_FIN_EOL_SZ; } if (!err) { outSz = PEM_BEGIN_SZ + nameLen + PEM_HDR_FIN_EOL_SZ + headerLen + pemLen + PEM_END_SZ + nameLen + PEM_HDR_FIN_EOL_SZ; } if (pem != NULL) XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER); return outSz; } #if !defined(NO_FILESYSTEM) int wolfSSL_PEM_read(XFILE fp, char **name, char **header, unsigned char **data, long *len) { int ret; WOLFSSL_BIO* bio; if (name == NULL || header == NULL || data == NULL || len == NULL) return WOLFSSL_FAILURE; bio = wolfSSL_BIO_new(wolfSSL_BIO_s_file()); if (bio == NULL) return 0; if (wolfSSL_BIO_set_fp(bio, fp, BIO_NOCLOSE) != WOLFSSL_SUCCESS) { wolfSSL_BIO_free(bio); bio = NULL; } ret = wolfSSL_PEM_read_bio(bio, name, header, data, len); if (bio != NULL) wolfSSL_BIO_free(bio); return ret; } int wolfSSL_PEM_write(XFILE fp, const char *name, const char *header, const unsigned char *data, long len) { int ret; WOLFSSL_BIO* bio; if (name == NULL || header == NULL || data == NULL) return 0; bio = wolfSSL_BIO_new(wolfSSL_BIO_s_file()); if (bio == NULL) return 0; if (wolfSSL_BIO_set_fp(bio, fp, BIO_NOCLOSE) != WOLFSSL_SUCCESS) { wolfSSL_BIO_free(bio); bio = NULL; } ret = wolfSSL_PEM_write_bio(bio, name, header, data, len); if (bio != NULL) wolfSSL_BIO_free(bio); return ret; } #endif #endif /* !NO_BIO */ int wolfSSL_PEM_get_EVP_CIPHER_INFO(const char* header, EncryptedInfo* cipher) { if (header == NULL || cipher == NULL) return WOLFSSL_FAILURE; XMEMSET(cipher, 0, sizeof(*cipher)); if (wc_EncryptedInfoParse(cipher, &header, XSTRLEN(header)) != 0) return WOLFSSL_FAILURE; return WOLFSSL_SUCCESS; } int wolfSSL_PEM_do_header(EncryptedInfo* cipher, unsigned char* data, long* len, wc_pem_password_cb* callback, void* ctx) { int ret = WOLFSSL_SUCCESS; char password[NAME_SZ]; int passwordSz; if (cipher == NULL || data == NULL || len == NULL || callback == NULL) return WOLFSSL_FAILURE; passwordSz = callback(password, sizeof(password), PEM_PASS_READ, ctx); if (passwordSz < 0) ret = WOLFSSL_FAILURE; if (ret == WOLFSSL_SUCCESS) { if (wc_BufferKeyDecrypt(cipher, data, (word32)*len, (byte*)password, passwordSz, WC_MD5) != 0) { ret = WOLFSSL_FAILURE; } } if (passwordSz > 0) XMEMSET(password, 0, passwordSz); return ret; } #ifndef NO_BIO /* * bp : bio to read X509 from * x : x509 to write to * cb : password call back for reading PEM * u : password * _AUX is for working with a trusted X509 certificate */ WOLFSSL_X509 *wolfSSL_PEM_read_bio_X509_AUX(WOLFSSL_BIO *bp, WOLFSSL_X509 **x, wc_pem_password_cb *cb, void *u) { WOLFSSL_ENTER("wolfSSL_PEM_read_bio_X509"); /* AUX info is; trusted/rejected uses, friendly name, private key id, * and potentially a stack of "other" info. wolfSSL does not store * friendly name or private key id yet in WOLFSSL_X509 for human * readability and does not support extra trusted/rejected uses for * root CA. */ return wolfSSL_PEM_read_bio_X509(bp, x, cb, u); } #endif /* !NO_BIO */ #endif /* OPENSSL_EXTRA || OPENSSL_ALL */ #endif /* !NO_CERTS */ /* NID variables are dependent on compatibility header files currently * * returns a pointer to a new WOLFSSL_ASN1_OBJECT struct on success and NULL * on fail */ WOLFSSL_ASN1_OBJECT* wolfSSL_OBJ_nid2obj(int id) { return wolfSSL_OBJ_nid2obj_ex(id, NULL); } WOLFSSL_LOCAL WOLFSSL_ASN1_OBJECT* wolfSSL_OBJ_nid2obj_ex(int id, WOLFSSL_ASN1_OBJECT* arg_obj) { word32 oidSz = 0; int nid = 0; const byte* oid; word32 type = 0; WOLFSSL_ASN1_OBJECT* obj = arg_obj; byte objBuf[MAX_OID_SZ + MAX_LENGTH_SZ + 1]; /* +1 for object tag */ word32 objSz = 0; const char* sName = NULL; int i; #ifdef WOLFSSL_DEBUG_OPENSSL WOLFSSL_ENTER("wolfSSL_OBJ_nid2obj()"); #endif for (i = 0; i < (int)WOLFSSL_OBJECT_INFO_SZ; i++) { if (wolfssl_object_info[i].nid == id) { nid = id; id = wolfssl_object_info[i].id; sName = wolfssl_object_info[i].sName; type = wolfssl_object_info[i].type; break; } } if (i == (int)WOLFSSL_OBJECT_INFO_SZ) { WOLFSSL_MSG("NID not in table"); #ifdef WOLFSSL_QT sName = NULL; type = id; #else return NULL; #endif } #ifdef HAVE_ECC if (type == 0 && wc_ecc_get_oid(id, &oid, &oidSz) > 0) { type = oidCurveType; } #endif /* HAVE_ECC */ if (sName != NULL) { if (XSTRLEN(sName) > WOLFSSL_MAX_SNAME - 1) { WOLFSSL_MSG("Attempted short name is too large"); return NULL; } } oid = OidFromId(id, type, &oidSz); /* set object ID to buffer */ if (obj == NULL){ obj = wolfSSL_ASN1_OBJECT_new(); if (obj == NULL) { WOLFSSL_MSG("Issue creating WOLFSSL_ASN1_OBJECT struct"); return NULL; } } obj->nid = nid; obj->type = id; obj->grp = type; obj->sName[0] = '\0'; if (sName != NULL) { XMEMCPY(obj->sName, (char*)sName, XSTRLEN((char*)sName)); } objBuf[0] = ASN_OBJECT_ID; objSz++; objSz += SetLength(oidSz, objBuf + 1); if (oidSz) { XMEMCPY(objBuf + objSz, oid, oidSz); objSz += oidSz; } if (obj->objSz == 0 || objSz != obj->objSz) { obj->objSz = objSz; if(((obj->dynamic & WOLFSSL_ASN1_DYNAMIC_DATA) != 0) || (obj->obj == NULL)) { if (obj->obj != NULL) XFREE((byte*)obj->obj, NULL, DYNAMIC_TYPE_ASN1); obj->obj = (byte*)XMALLOC(obj->objSz, NULL, DYNAMIC_TYPE_ASN1); if (obj->obj == NULL) { wolfSSL_ASN1_OBJECT_free(obj); return NULL; } obj->dynamic |= WOLFSSL_ASN1_DYNAMIC_DATA ; } else { obj->dynamic &= ~WOLFSSL_ASN1_DYNAMIC_DATA ; } } XMEMCPY((byte*)obj->obj, objBuf, obj->objSz); (void)type; return obj; } static const char* oid_translate_num_to_str(const char* oid) { const struct oid_dict { const char* num; const char* desc; } oid_dict[] = { { "2.5.29.37.0", "Any Extended Key Usage" }, { "1.3.6.1.5.5.7.3.1", "TLS Web Server Authentication" }, { "1.3.6.1.5.5.7.3.2", "TLS Web Client Authentication" }, { "1.3.6.1.5.5.7.3.3", "Code Signing" }, { "1.3.6.1.5.5.7.3.4", "E-mail Protection" }, { "1.3.6.1.5.5.7.3.8", "Time Stamping" }, { "1.3.6.1.5.5.7.3.9", "OCSP Signing" }, { NULL, NULL } }; const struct oid_dict* idx; for (idx = oid_dict; idx->num != NULL; idx++) { if (!XSTRCMP(oid, idx->num)) { return idx->desc; } } return NULL; } static int wolfssl_obj2txt_numeric(char *buf, int bufLen, const WOLFSSL_ASN1_OBJECT *a) { int bufSz; int length; word32 idx = 0; byte tag; if (GetASNTag(a->obj, &idx, &tag, a->objSz) != 0) { return WOLFSSL_FAILURE; } if (tag != ASN_OBJECT_ID) { WOLFSSL_MSG("Bad ASN1 Object"); return WOLFSSL_FAILURE; } if (GetLength((const byte*)a->obj, &idx, &length, a->objSz) < 0 || length < 0) { return ASN_PARSE_E; } if (bufLen < MAX_OID_STRING_SZ) { bufSz = bufLen - 1; } else { bufSz = MAX_OID_STRING_SZ; } if ((bufSz = DecodePolicyOID(buf, (word32)bufSz, a->obj + idx, (word32)length)) <= 0) { WOLFSSL_MSG("Error decoding OID"); return WOLFSSL_FAILURE; } buf[bufSz] = '\0'; return bufSz; } /* If no_name is one then use numerical form, otherwise short name. * * Returns the buffer size on success, WOLFSSL_FAILURE on error */ int wolfSSL_OBJ_obj2txt(char *buf, int bufLen, const WOLFSSL_ASN1_OBJECT *a, int no_name) { int bufSz; const char* desc; const char* name; WOLFSSL_ENTER("wolfSSL_OBJ_obj2txt()"); if (buf == NULL || bufLen <= 1 || a == NULL) { WOLFSSL_MSG("Bad input argument"); return WOLFSSL_FAILURE; } if (no_name == 1) { return wolfssl_obj2txt_numeric(buf, bufLen, a); } /* return long name unless using x509small, then return short name */ #if defined(OPENSSL_EXTRA_X509_SMALL) && !defined(OPENSSL_EXTRA) name = a->sName; #else name = wolfSSL_OBJ_nid2ln(wolfSSL_OBJ_obj2nid(a)); #endif if (name == NULL) { WOLFSSL_MSG("Name not found"); bufSz = 0; } else if (XSTRLEN(name) + 1 < (word32)bufLen - 1) { bufSz = (int)XSTRLEN(name); } else { bufSz = bufLen - 1; } if (bufSz) { XMEMCPY(buf, name, bufSz); } else if (a->type == GEN_DNS || a->type == GEN_EMAIL || a->type == GEN_URI) { bufSz = (int)XSTRLEN((const char*)a->obj); XMEMCPY(buf, a->obj, min(bufSz, bufLen)); } else if ((bufSz = wolfssl_obj2txt_numeric(buf, bufLen, a)) > 0) { if ((desc = oid_translate_num_to_str(buf))) { bufSz = (int)XSTRLEN(desc); bufSz = min(bufSz, bufLen - 1); XMEMCPY(buf, desc, bufSz); } } buf[bufSz] = '\0'; return bufSz; } #endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ #if defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY) || \ defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(HAVE_STUNNEL) || \ defined(WOLFSSL_NGINX) || defined(HAVE_POCO_LIB) || \ defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_WPAS_SMALL) /* Returns the long name that corresponds with an ASN1_OBJECT nid value. * n : NID value of ASN1_OBJECT to search */ const char* wolfSSL_OBJ_nid2ln(int n) { const WOLFSSL_ObjectInfo *obj_info = wolfssl_object_info; size_t i; WOLFSSL_ENTER("wolfSSL_OBJ_nid2ln"); for (i = 0; i < WOLFSSL_OBJECT_INFO_SZ; i++, obj_info++) { if (obj_info->nid == n) { return obj_info->lName; } } WOLFSSL_MSG("NID not found in table"); return NULL; } #endif /* OPENSSL_EXTRA, HAVE_LIGHTY, WOLFSSL_MYSQL_COMPATIBLE, HAVE_STUNNEL, WOLFSSL_NGINX, HAVE_POCO_LIB, WOLFSSL_HAPROXY, WOLFSSL_WPAS_SMALL */ #if defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY) || \ defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(HAVE_STUNNEL) || \ defined(WOLFSSL_NGINX) || defined(HAVE_POCO_LIB) || \ defined(WOLFSSL_HAPROXY) char wolfSSL_CTX_use_certificate(WOLFSSL_CTX *ctx, WOLFSSL_X509 *x) { int ret; WOLFSSL_ENTER("wolfSSL_CTX_use_certificate"); if (!ctx || !x || !x->derCert) { WOLFSSL_MSG("Bad parameter"); return WOLFSSL_FAILURE; } FreeDer(&ctx->certificate); /* Make sure previous is free'd */ ret = AllocDer(&ctx->certificate, x->derCert->length, CERT_TYPE, ctx->heap); if (ret != 0) return WOLFSSL_FAILURE; XMEMCPY(ctx->certificate->buffer, x->derCert->buffer, x->derCert->length); #ifdef KEEP_OUR_CERT if (ctx->ourCert != NULL && ctx->ownOurCert) { wolfSSL_X509_free(ctx->ourCert); } #ifndef WOLFSSL_X509_STORE_CERTS ctx->ourCert = x; if (wolfSSL_X509_up_ref(x) != 1) { return WOLFSSL_FAILURE; } #else ctx->ourCert = wolfSSL_X509_d2i(NULL, x->derCert->buffer,x->derCert->length); if(ctx->ourCert == NULL){ return WOLFSSL_FAILURE; } #endif /* We own the cert because either we up its reference counter * or we create our own copy of the cert object. */ ctx->ownOurCert = 1; #endif /* Update the available options with public keys. */ switch (x->pubKeyOID) { case RSAk: ctx->haveRSA = 1; break; #ifdef HAVE_ED25519 case ED25519k: #endif #ifdef HAVE_ED448 case ED448k: #endif case ECDSAk: ctx->haveECC = 1; #if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448) ctx->pkCurveOID = x->pkCurveOID; #endif break; } return WOLFSSL_SUCCESS; } static int PushCertToDerBuffer(DerBuffer** inOutDer, int weOwn, byte* cert, word32 certSz, void* heap) { int ret; DerBuffer* inChain = NULL; DerBuffer* der = NULL; word32 len = 0; if (inOutDer == NULL) return BAD_FUNC_ARG; inChain = *inOutDer; if (inChain != NULL) len = inChain->length; ret = AllocDer(&der, len + CERT_HEADER_SZ + certSz, CERT_TYPE, heap); if (ret != 0) { WOLFSSL_MSG("AllocDer error"); return ret; } if (inChain != NULL) XMEMCPY(der->buffer, inChain->buffer, len); c32to24(certSz, der->buffer + len); XMEMCPY(der->buffer + len + CERT_HEADER_SZ, cert, certSz); if (weOwn) FreeDer(inOutDer); *inOutDer = der; return WOLFSSL_SUCCESS; } /** * wolfSSL_CTX_add1_chain_cert makes a copy of the cert so we free it * on success */ int wolfSSL_CTX_add0_chain_cert(WOLFSSL_CTX* ctx, WOLFSSL_X509* x509) { WOLFSSL_ENTER("wolfSSL_CTX_add0_chain_cert"); if (wolfSSL_CTX_add1_chain_cert(ctx, x509) != WOLFSSL_SUCCESS) { return WOLFSSL_FAILURE; } wolfSSL_X509_free(x509); return WOLFSSL_SUCCESS; } int wolfSSL_CTX_add1_chain_cert(WOLFSSL_CTX* ctx, WOLFSSL_X509* x509) { int ret; WOLFSSL_ENTER("wolfSSL_CTX_add1_chain_cert"); if (ctx == NULL || x509 == NULL || x509->derCert == NULL) { return WOLFSSL_FAILURE; } if (ctx->certificate == NULL) ret = (int)wolfSSL_CTX_use_certificate(ctx, x509); else { if (wolfSSL_X509_up_ref(x509) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("wolfSSL_X509_up_ref error"); return WOLFSSL_FAILURE; } ret = wolfSSL_CTX_load_verify_buffer(ctx, x509->derCert->buffer, x509->derCert->length, WOLFSSL_FILETYPE_ASN1); if (ret == WOLFSSL_SUCCESS) { /* push to ctx->certChain */ ret = PushCertToDerBuffer(&ctx->certChain, 1, x509->derCert->buffer, x509->derCert->length, ctx->heap); } /* Store cert to free it later */ if (ret == WOLFSSL_SUCCESS && ctx->x509Chain == NULL) { ctx->x509Chain = wolfSSL_sk_X509_new(); if (ctx->x509Chain == NULL) { WOLFSSL_MSG("wolfSSL_sk_X509_new error"); ret = WOLFSSL_FAILURE; } } if (ret == WOLFSSL_SUCCESS && wolfSSL_sk_X509_push(ctx->x509Chain, x509) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("wolfSSL_sk_X509_push error"); ret = WOLFSSL_FAILURE; } if (ret != WOLFSSL_SUCCESS) wolfSSL_X509_free(x509); /* Decrease ref counter */ } return (ret == WOLFSSL_SUCCESS) ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; } #ifdef KEEP_OUR_CERT int wolfSSL_add0_chain_cert(WOLFSSL* ssl, WOLFSSL_X509* x509) { int ret; WOLFSSL_ENTER("wolfSSL_add0_chain_cert"); if (ssl == NULL || ssl->ctx == NULL || x509 == NULL || x509->derCert == NULL) return WOLFSSL_FAILURE; if (ssl->buffers.certificate == NULL) { ret = wolfSSL_use_certificate(ssl, x509); /* Store cert to free it later */ if (ret == WOLFSSL_SUCCESS) { if (ssl->buffers.weOwnCert) wolfSSL_X509_free(ssl->ourCert); ssl->ourCert = x509; ssl->buffers.weOwnCert = 1; } } else { ret = PushCertToDerBuffer(&ssl->buffers.certChain, ssl->buffers.weOwnCertChain, x509->derCert->buffer, x509->derCert->length, ssl->heap); if (ret == WOLFSSL_SUCCESS) { ssl->buffers.weOwnCertChain = 1; /* Store cert to free it later */ if (ssl->ourCertChain == NULL) { ssl->ourCertChain = wolfSSL_sk_X509_new(); if (ssl->ourCertChain == NULL) { WOLFSSL_MSG("wolfSSL_sk_X509_new error"); return WOLFSSL_FAILURE; } } if (wolfSSL_sk_X509_push(ssl->ourCertChain, x509) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("wolfSSL_sk_X509_push error"); return WOLFSSL_FAILURE; } } } return ret == WOLFSSL_SUCCESS ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; } int wolfSSL_add1_chain_cert(WOLFSSL* ssl, WOLFSSL_X509* x509) { int ret; WOLFSSL_ENTER("wolfSSL_add1_chain_cert"); if (ssl == NULL || ssl->ctx == NULL || x509 == NULL || x509->derCert == NULL) return WOLFSSL_FAILURE; if (wolfSSL_X509_up_ref(x509) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("wolfSSL_X509_up_ref error"); return WOLFSSL_FAILURE; } ret = wolfSSL_add0_chain_cert(ssl, x509); /* Decrease ref counter on error */ if (ret != WOLFSSL_SUCCESS) wolfSSL_X509_free(x509); return ret; } #endif /* Return the corresponding short name for the nid . * or NULL if short name can't be found. */ const char * wolfSSL_OBJ_nid2sn(int n) { const WOLFSSL_ObjectInfo *obj_info = wolfssl_object_info; size_t i; WOLFSSL_ENTER("wolfSSL_OBJ_nid2sn"); if (n == NID_md5) { /* NID_surname == NID_md5 and NID_surname comes before NID_md5 in * wolfssl_object_info. As a result, the loop below will incorrectly * return "SN" instead of "MD5." NID_surname isn't the true OpenSSL * NID, but other functions rely on this table and modifying it to * conform with OpenSSL's NIDs isn't trivial. */ return "MD5"; } for (i = 0; i < WOLFSSL_OBJECT_INFO_SZ; i++, obj_info++) { if (obj_info->nid == n) { return obj_info->sName; } } WOLFSSL_MSG("SN not found"); return NULL; } #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) int wolfSSL_OBJ_sn2nid(const char *sn) { WOLFSSL_ENTER("wolfSSL_OBJ_sn2nid"); if (sn == NULL) return NID_undef; return wc_OBJ_sn2nid(sn); } #endif size_t wolfSSL_OBJ_length(const WOLFSSL_ASN1_OBJECT* o) { size_t ret = 0; int err = 0; word32 idx = 0; int len = 0; WOLFSSL_ENTER("wolfSSL_OBJ_length"); if (o == NULL || o->obj == NULL) { WOLFSSL_MSG("Bad argument."); err = 1; } if (err == 0 && GetASNObjectId(o->obj, &idx, &len, o->objSz)) { WOLFSSL_MSG("Error parsing ASN.1 header."); err = 1; } if (err == 0) { ret = len; } WOLFSSL_LEAVE("wolfSSL_OBJ_length", (int)ret); return ret; } const unsigned char* wolfSSL_OBJ_get0_data(const WOLFSSL_ASN1_OBJECT* o) { const unsigned char* ret = NULL; int err = 0; word32 idx = 0; int len = 0; WOLFSSL_ENTER("wolfSSL_OBJ_get0_data"); if (o == NULL || o->obj == NULL) { WOLFSSL_MSG("Bad argument."); err = 1; } if (err == 0 && GetASNObjectId(o->obj, &idx, &len, o->objSz)) { WOLFSSL_MSG("Error parsing ASN.1 header."); err = 1; } if (err == 0) { ret = o->obj + idx; } return ret; } /* Gets the NID value that corresponds with the ASN1 object. * * o ASN1 object to get NID of * * Return NID on success and a negative value on failure */ int wolfSSL_OBJ_obj2nid(const WOLFSSL_ASN1_OBJECT *o) { word32 oid = 0; word32 idx = 0; int ret; #ifdef WOLFSSL_DEBUG_OPENSSL WOLFSSL_ENTER("wolfSSL_OBJ_obj2nid"); #endif if (o == NULL) { return -1; } #ifdef WOLFSSL_QT if (o->grp == oidCertExtType) { /* If nid is an unknown extension, return NID_undef */ if (wolfSSL_OBJ_nid2sn(o->nid) == NULL) return NID_undef; } #endif if (o->nid > 0) return o->nid; if ((ret = GetObjectId(o->obj, &idx, &oid, o->grp, o->objSz)) < 0) { if (ret == ASN_OBJECT_ID_E) { /* Put ASN object tag in front and try again */ int len = SetObjectId(o->objSz, NULL) + o->objSz; byte* buf = (byte*)XMALLOC(len, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (!buf) { WOLFSSL_MSG("malloc error"); return -1; } idx = SetObjectId(o->objSz, buf); XMEMCPY(buf + idx, o->obj, o->objSz); idx = 0; ret = GetObjectId(buf, &idx, &oid, o->grp, len); XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (ret < 0) { WOLFSSL_MSG("Issue getting OID of object"); return -1; } } else { WOLFSSL_MSG("Issue getting OID of object"); return -1; } } return oid2nid(oid, o->grp); } /* Return the corresponding NID for the long name * or NID_undef if NID can't be found. */ int wolfSSL_OBJ_ln2nid(const char *ln) { const WOLFSSL_ObjectInfo *obj_info = wolfssl_object_info; size_t i, lnlen; WOLFSSL_ENTER("wolfSSL_OBJ_ln2nid"); if (ln && (lnlen = XSTRLEN(ln)) > 0) { /* Accept input like "/commonName=" */ if (ln[0] == '/') { ln++; lnlen--; } if (lnlen) { if (ln[lnlen-1] == '=') { lnlen--; } for (i = 0; i < WOLFSSL_OBJECT_INFO_SZ; i++, obj_info++) { if (lnlen == XSTRLEN(obj_info->lName) && XSTRNCMP(ln, obj_info->lName, lnlen) == 0) { return obj_info->nid; } } } } return NID_undef; } /* compares two objects, return 0 if equal */ int wolfSSL_OBJ_cmp(const WOLFSSL_ASN1_OBJECT* a, const WOLFSSL_ASN1_OBJECT* b) { WOLFSSL_ENTER("wolfSSL_OBJ_cmp"); if (a && b && a->obj && b->obj) { if (a->objSz == b->objSz) { return XMEMCMP(a->obj, b->obj, a->objSz); } else if (a->type == EXT_KEY_USAGE_OID || b->type == EXT_KEY_USAGE_OID) { /* Special case for EXT_KEY_USAGE_OID so that * cmp will be treated as a substring search */ /* Used in libest to check for id-kp-cmcRA in * EXT_KEY_USAGE extension */ unsigned int idx; const byte* s; /* shorter */ unsigned int sLen; const byte* l; /* longer */ unsigned int lLen; if (a->objSz > b->objSz) { s = b->obj; sLen = b->objSz; l = a->obj; lLen = a->objSz; } else { s = a->obj; sLen = a->objSz; l = b->obj; lLen = b->objSz; } for (idx = 0; idx <= lLen - sLen; idx++) { if (XMEMCMP(l + idx, s, sLen) == 0) { /* Found substring */ return 0; } } } } return WOLFSSL_FATAL_ERROR; } #endif /* OPENSSL_EXTRA, HAVE_LIGHTY, WOLFSSL_MYSQL_COMPATIBLE, HAVE_STUNNEL, WOLFSSL_NGINX, HAVE_POCO_LIB, WOLFSSL_HAPROXY */ #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) || \ defined(HAVE_LIGHTY) || defined(WOLFSSL_MYSQL_COMPATIBLE) || \ defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || \ defined(HAVE_POCO_LIB) || defined(WOLFSSL_HAPROXY) /* Gets the NID value that is related to the OID string passed in. Example * string would be "2.5.29.14" for subject key ID. * * returns NID value on success and NID_undef on error */ int wolfSSL_OBJ_txt2nid(const char* s) { unsigned int i; #ifdef WOLFSSL_CERT_EXT int ret; unsigned int sum = 0; unsigned int outSz = MAX_OID_SZ; unsigned char out[MAX_OID_SZ]; #endif WOLFSSL_ENTER("OBJ_txt2nid"); if (s == NULL) { return NID_undef; } #ifdef WOLFSSL_CERT_EXT ret = EncodePolicyOID(out, &outSz, s, NULL); if (ret == 0) { /* sum OID */ for (i = 0; i < outSz; i++) { sum += out[i]; } } #endif /* WOLFSSL_CERT_EXT */ /* get the group that the OID's sum is in * @TODO possible conflict with multiples */ for (i = 0; i < WOLFSSL_OBJECT_INFO_SZ; i++) { int len; #ifdef WOLFSSL_CERT_EXT if (ret == 0) { if (wolfssl_object_info[i].id == (int)sum) { return wolfssl_object_info[i].nid; } } #endif /* try as a short name */ len = (int)XSTRLEN(s); if ((int)XSTRLEN(wolfssl_object_info[i].sName) == len && XSTRNCMP(wolfssl_object_info[i].sName, s, len) == 0) { return wolfssl_object_info[i].nid; } /* try as a long name */ if ((int)XSTRLEN(wolfssl_object_info[i].lName) == len && XSTRNCMP(wolfssl_object_info[i].lName, s, len) == 0) { return wolfssl_object_info[i].nid; } } return NID_undef; } #endif #if defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY) || \ defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(HAVE_STUNNEL) || \ defined(WOLFSSL_NGINX) || defined(HAVE_POCO_LIB) || \ defined(WOLFSSL_HAPROXY) /* Creates new ASN1_OBJECT from short name, long name, or text * representation of oid. If no_name is 0, then short name, long name, and * numerical value of oid are interpreted. If no_name is 1, then only the * numerical value of the oid is interpreted. * * Returns pointer to ASN1_OBJECT on success, or NULL on error. */ #if defined(WOLFSSL_CERT_EXT) && defined(WOLFSSL_CERT_GEN) WOLFSSL_ASN1_OBJECT* wolfSSL_OBJ_txt2obj(const char* s, int no_name) { int i, ret; int nid = NID_undef; unsigned int outSz = MAX_OID_SZ; unsigned char out[MAX_OID_SZ]; WOLFSSL_ASN1_OBJECT* obj; WOLFSSL_ENTER("wolfSSL_OBJ_txt2obj"); if (s == NULL) return NULL; /* If s is numerical value, try to sum oid */ ret = EncodePolicyOID(out, &outSz, s, NULL); if (ret == 0 && outSz > 0) { /* If numerical encode succeeded then just * create object from that because sums are * not unique and can cause confusion. */ obj = wolfSSL_ASN1_OBJECT_new(); if (obj == NULL) { WOLFSSL_MSG("Issue creating WOLFSSL_ASN1_OBJECT struct"); return NULL; } obj->dynamic |= WOLFSSL_ASN1_DYNAMIC; obj->obj = (byte*)XMALLOC(1 + MAX_LENGTH_SZ + outSz, NULL, DYNAMIC_TYPE_ASN1); if (obj->obj == NULL) { wolfSSL_ASN1_OBJECT_free(obj); return NULL; } obj->dynamic |= WOLFSSL_ASN1_DYNAMIC_DATA ; i = SetObjectId(outSz, (byte*)obj->obj); XMEMCPY((byte*)obj->obj + i, out, outSz); obj->objSz = i + outSz; return obj; } /* TODO: update short names in wolfssl_object_info and check OID sums are correct */ for (i = 0; i < (int)WOLFSSL_OBJECT_INFO_SZ; i++) { /* Short name, long name, and numerical value are interpreted */ if (no_name == 0 && ((XSTRCMP(s, wolfssl_object_info[i].sName) == 0) || (XSTRCMP(s, wolfssl_object_info[i].lName) == 0))) { nid = wolfssl_object_info[i].nid; } } if (nid != NID_undef) return wolfSSL_OBJ_nid2obj(nid); return NULL; } #endif /* compatibility function. Its intended use is to remove OID's from an * internal table that have been added with OBJ_create. wolfSSL manages its * own internal OID values and does not currently support OBJ_create. */ void wolfSSL_OBJ_cleanup(void) { WOLFSSL_ENTER("wolfSSL_OBJ_cleanup()"); } #ifndef NO_WOLFSSL_STUB int wolfSSL_OBJ_create(const char *oid, const char *sn, const char *ln) { (void)oid; (void)sn; (void)ln; WOLFSSL_STUB("wolfSSL_OBJ_create"); return WOLFSSL_FAILURE; } #endif void wolfSSL_set_verify_depth(WOLFSSL *ssl, int depth) { #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) WOLFSSL_ENTER("wolfSSL_set_verify_depth"); ssl->options.verifyDepth = (byte)depth; #endif } #endif /* OPENSSL_ALL || HAVE_LIGHTY || WOLFSSL_MYSQL_COMPATIBLE || HAVE_STUNNEL || WOLFSSL_NGINX || HAVE_POCO_LIB || WOLFSSL_HAPROXY */ #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) || \ defined(HAVE_LIGHTY) || defined(WOLFSSL_MYSQL_COMPATIBLE) || \ defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || \ defined(HAVE_POCO_LIB) || defined(WOLFSSL_HAPROXY) WOLFSSL_ASN1_OBJECT * wolfSSL_X509_NAME_ENTRY_get_object(WOLFSSL_X509_NAME_ENTRY *ne) { WOLFSSL_ASN1_OBJECT* obj = NULL; #ifdef WOLFSSL_DEBUG_OPENSSL WOLFSSL_ENTER("wolfSSL_X509_NAME_ENTRY_get_object"); #endif if (ne == NULL) return NULL; obj = wolfSSL_OBJ_nid2obj_ex(ne->nid, ne->object); if (obj != NULL) { obj->nid = ne->nid; return obj; } return NULL; } #endif /* OPENSSL_ALL || HAVE_LIGHTY || WOLFSSL_MYSQL_COMPATIBLE || HAVE_STUNNEL || WOLFSSL_NGINX || HAVE_POCO_LIB || WOLFSSL_HAPROXY */ #ifdef OPENSSL_EXTRA /* wolfSSL uses negative values for error states. This function returns an * unsigned type so the value returned is the absolute value of the error. */ unsigned long wolfSSL_ERR_peek_last_error_line(const char **file, int *line) { WOLFSSL_ENTER("wolfSSL_ERR_peek_last_error"); (void)line; (void)file; #ifdef WOLFSSL_HAVE_ERROR_QUEUE { int ret; if ((ret = wc_PeekErrorNode(-1, file, NULL, line)) < 0) { WOLFSSL_MSG("Issue peeking at error node in queue"); return 0; } printf("ret from peek error node = %d\n", ret); #if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) if (ret == -ASN_NO_PEM_HEADER) return (ERR_LIB_PEM << 24) | PEM_R_NO_START_LINE; #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; } #endif return (unsigned long)ret; } #else return (unsigned long)(0 - NOT_COMPILED_IN); #endif } #ifndef NO_CERTS int wolfSSL_CTX_use_PrivateKey(WOLFSSL_CTX *ctx, WOLFSSL_EVP_PKEY *pkey) { WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey"); if (ctx == NULL || pkey == NULL) { return WOLFSSL_FAILURE; } switch (pkey->type) { #if defined(WOLFSSL_KEY_GEN) && !defined(HAVE_USER_RSA) && !defined(NO_RSA) case EVP_PKEY_RSA: WOLFSSL_MSG("populating RSA key"); if (PopulateRSAEvpPkeyDer(pkey) != WOLFSSL_SUCCESS) return WOLFSSL_FAILURE; break; #endif /* (WOLFSSL_KEY_GEN || OPENSSL_EXTRA) && !NO_RSA */ #if !defined(HAVE_SELFTEST) && (defined(WOLFSSL_KEY_GEN) || \ defined(WOLFSSL_CERT_GEN)) && !defined(NO_DSA) case EVP_PKEY_DSA: break; #endif /* !HAVE_SELFTEST && (WOLFSSL_KEY_GEN || WOLFSSL_CERT_GEN) && !NO_DSA */ #ifdef HAVE_ECC case EVP_PKEY_EC: WOLFSSL_MSG("populating ECC key"); if (ECC_populate_EVP_PKEY(pkey, pkey->ecc) != WOLFSSL_SUCCESS) return WOLFSSL_FAILURE; break; #endif default: return WOLFSSL_FAILURE; } if (pkey->pkey.ptr != NULL) { /* ptr for WOLFSSL_EVP_PKEY struct is expected to be DER format */ return wolfSSL_CTX_use_PrivateKey_buffer(ctx, (const unsigned char*)pkey->pkey.ptr, pkey->pkey_sz, SSL_FILETYPE_ASN1); } WOLFSSL_MSG("wolfSSL private key not set"); return BAD_FUNC_ARG; } #endif /* !NO_CERTS */ #endif /* OPENSSL_EXTRA */ #if defined(HAVE_EX_DATA) && \ (defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || \ defined(WOLFSSL_HAPROXY) || defined(OPENSSL_EXTRA) || \ defined(HAVE_LIGHTY)) || defined(HAVE_EX_DATA) || \ defined(WOLFSSL_WPAS_SMALL) /** * get_ex_new_index is a helper function for the following * xx_get_ex_new_index functions: * - wolfSSL_CRYPTO_get_ex_new_index * - wolfSSL_CTX_get_ex_new_index * - wolfSSL_get_ex_new_index * Issues a unique index number for the specified class-index. * Returns an index number greater or equal to zero on success, * -1 on failure. */ int wolfssl_get_ex_new_index(int class_index) { /* index counter for each class index*/ static int ctx_idx = 0; static int ssl_idx = 0; static int ssl_session_idx = 0; static int x509_idx = 0; int idx = -1; switch(class_index) { case WOLF_CRYPTO_EX_INDEX_SSL: idx = ssl_idx++; break; case WOLF_CRYPTO_EX_INDEX_SSL_CTX: idx = ctx_idx++; break; case WOLF_CRYPTO_EX_INDEX_X509: idx = x509_idx++; break; case WOLF_CRYPTO_EX_INDEX_SSL_SESSION: idx = ssl_session_idx++; break; /* following class indexes are not supoprted */ case WOLF_CRYPTO_EX_INDEX_X509_STORE: case WOLF_CRYPTO_EX_INDEX_X509_STORE_CTX: case WOLF_CRYPTO_EX_INDEX_DH: case WOLF_CRYPTO_EX_INDEX_DSA: case WOLF_CRYPTO_EX_INDEX_EC_KEY: case WOLF_CRYPTO_EX_INDEX_RSA: case WOLF_CRYPTO_EX_INDEX_ENGINE: case WOLF_CRYPTO_EX_INDEX_UI: case WOLF_CRYPTO_EX_INDEX_BIO: case WOLF_CRYPTO_EX_INDEX_APP: case WOLF_CRYPTO_EX_INDEX_UI_METHOD: case WOLF_CRYPTO_EX_INDEX_DRBG: default: break; } return idx; } #endif /* HAVE_EX_DATA || WOLFSSL_WPAS_SMALL */ #if defined(HAVE_EX_DATA) || defined(WOLFSSL_WPAS_SMALL) void* wolfSSL_CTX_get_ex_data(const WOLFSSL_CTX* ctx, int idx) { WOLFSSL_ENTER("wolfSSL_CTX_get_ex_data"); #ifdef HAVE_EX_DATA if(ctx != NULL) { return wolfSSL_CRYPTO_get_ex_data(&ctx->ex_data, idx); } #else (void)ctx; (void)idx; #endif return NULL; } int wolfSSL_CTX_get_ex_new_index(long idx, void* arg, void* a, void* b, void* c) { WOLFSSL_ENTER("wolfSSL_CTX_get_ex_new_index"); (void)idx; (void)arg; (void)a; (void)b; (void)c; return wolfssl_get_ex_new_index(WOLF_CRYPTO_EX_INDEX_SSL_CTX); } /* Return the index that can be used for the WOLFSSL structure to store * application data. * */ int wolfSSL_get_ex_new_index(long argValue, void* arg, WOLFSSL_CRYPTO_EX_new* cb1, WOLFSSL_CRYPTO_EX_dup* cb2, WOLFSSL_CRYPTO_EX_free* cb3) { WOLFSSL_ENTER("wolfSSL_get_ex_new_index"); (void)argValue; (void)arg; (void)cb1; (void)cb2; (void)cb3; return wolfssl_get_ex_new_index(WOLF_CRYPTO_EX_INDEX_SSL); } int wolfSSL_CTX_set_ex_data(WOLFSSL_CTX* ctx, int idx, void* data) { WOLFSSL_ENTER("wolfSSL_CTX_set_ex_data"); #ifdef HAVE_EX_DATA if (ctx != NULL) { return wolfSSL_CRYPTO_set_ex_data(&ctx->ex_data, idx, data); } #else (void)ctx; (void)idx; (void)data; #endif return WOLFSSL_FAILURE; } #ifdef HAVE_EX_DATA_CLEANUP_HOOKS int wolfSSL_CTX_set_ex_data_with_cleanup( WOLFSSL_CTX* ctx, int idx, void* data, wolfSSL_ex_data_cleanup_routine_t cleanup_routine) { WOLFSSL_ENTER("wolfSSL_CTX_set_ex_data_with_cleanup"); if (ctx != NULL) { return wolfSSL_CRYPTO_set_ex_data_with_cleanup(&ctx->ex_data, idx, data, cleanup_routine); } return WOLFSSL_FAILURE; } #endif /* HAVE_EX_DATA_CLEANUP_HOOKS */ #endif /* defined(HAVE_EX_DATA) || defined(WOLFSSL_WPAS_SMALL) */ #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) /* Returns char* to app data stored in ex[0]. * * ssl WOLFSSL structure to get app data from */ void* wolfSSL_get_app_data(const WOLFSSL *ssl) { /* checkout exdata stuff... */ WOLFSSL_ENTER("wolfSSL_get_app_data"); return wolfSSL_get_ex_data(ssl, 0); } /* Set ex array 0 to have app data * * ssl WOLFSSL struct to set app data in * arg data to be stored * * Returns WOLFSSL_SUCCESS on success and SSL_FAILURE on failure */ int wolfSSL_set_app_data(WOLFSSL *ssl, void* arg) { WOLFSSL_ENTER("wolfSSL_set_app_data"); return wolfSSL_set_ex_data(ssl, 0, arg); } #endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ #if defined(HAVE_EX_DATA) || defined(OPENSSL_EXTRA) || \ defined(OPENSSL_EXTRA_X509_SMALL) || defined(WOLFSSL_WPAS_SMALL) int wolfSSL_set_ex_data(WOLFSSL* ssl, int idx, void* data) { WOLFSSL_ENTER("wolfSSL_set_ex_data"); #ifdef HAVE_EX_DATA if (ssl != NULL) { return wolfSSL_CRYPTO_set_ex_data(&ssl->ex_data, idx, data); } #else WOLFSSL_MSG("HAVE_EX_DATA macro is not defined"); (void)ssl; (void)idx; (void)data; #endif return WOLFSSL_FAILURE; } #ifdef HAVE_EX_DATA_CLEANUP_HOOKS int wolfSSL_set_ex_data_with_cleanup( WOLFSSL* ssl, int idx, void* data, wolfSSL_ex_data_cleanup_routine_t cleanup_routine) { WOLFSSL_ENTER("wolfSSL_set_ex_data_with_cleanup"); if (ssl != NULL) { return wolfSSL_CRYPTO_set_ex_data_with_cleanup(&ssl->ex_data, idx, data, cleanup_routine); } return WOLFSSL_FAILURE; } #endif /* HAVE_EX_DATA_CLEANUP_HOOKS */ void* wolfSSL_get_ex_data(const WOLFSSL* ssl, int idx) { WOLFSSL_ENTER("wolfSSL_get_ex_data"); #ifdef HAVE_EX_DATA if (ssl != NULL) { return wolfSSL_CRYPTO_get_ex_data(&ssl->ex_data, idx); } #else WOLFSSL_MSG("HAVE_EX_DATA macro is not defined"); (void)ssl; (void)idx; #endif return 0; } #endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL || WOLFSSL_WPAS_SMALL */ #if defined(HAVE_LIGHTY) || defined(HAVE_STUNNEL) \ || defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(OPENSSL_EXTRA) #if defined(OPENSSL_EXTRA) && !defined(NO_DH) /* Initialize ctx->dh with dh's params. Return WOLFSSL_SUCCESS on ok */ long wolfSSL_CTX_set_tmp_dh(WOLFSSL_CTX* ctx, WOLFSSL_DH* dh) { int pSz, gSz; byte *p, *g; int ret=0; WOLFSSL_ENTER("wolfSSL_CTX_set_tmp_dh"); if(!ctx || !dh) return BAD_FUNC_ARG; /* Get needed size for p and g */ pSz = wolfSSL_BN_bn2bin(dh->p, NULL); gSz = wolfSSL_BN_bn2bin(dh->g, NULL); if(pSz <= 0 || gSz <= 0) return WOLFSSL_FATAL_ERROR; p = (byte*)XMALLOC(pSz, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); if(!p) return MEMORY_E; g = (byte*)XMALLOC(gSz, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); if(!g) { XFREE(p, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); return MEMORY_E; } pSz = wolfSSL_BN_bn2bin(dh->p, p); gSz = wolfSSL_BN_bn2bin(dh->g, g); if(pSz >= 0 && gSz >= 0) /* Conversion successful */ ret = wolfSSL_CTX_SetTmpDH(ctx, p, pSz, g, gSz); XFREE(p, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); XFREE(g, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); return pSz > 0 && gSz > 0 ? ret : WOLFSSL_FATAL_ERROR; } #endif /* OPENSSL_EXTRA && !NO_DH */ /* returns the enum value associated with handshake state * * ssl the WOLFSSL structure to get state of */ int wolfSSL_get_state(const WOLFSSL* ssl) { WOLFSSL_ENTER("wolfSSL_get_state"); if (ssl == NULL) { WOLFSSL_MSG("Null argument passed in"); return SSL_FAILURE; } return ssl->options.handShakeState; } #endif /* HAVE_LIGHTY || HAVE_STUNNEL || WOLFSSL_MYSQL_COMPATIBLE */ #ifdef OPENSSL_EXTRA void wolfSSL_certs_clear(WOLFSSL* ssl) { WOLFSSL_ENTER("wolfSSL_certs_clear()"); if (ssl == NULL) return; /* ctx still owns certificate, certChain, key, dh, and cm */ if (ssl->buffers.weOwnCert) FreeDer(&ssl->buffers.certificate); ssl->buffers.certificate = NULL; if (ssl->buffers.weOwnCertChain) FreeDer(&ssl->buffers.certChain); ssl->buffers.certChain = NULL; #ifdef WOLFSSL_TLS13 ssl->buffers.certChainCnt = 0; #endif if (ssl->buffers.weOwnKey) FreeDer(&ssl->buffers.key); ssl->buffers.key = NULL; ssl->buffers.keyType = 0; ssl->buffers.keyId = 0; ssl->buffers.keyLabel = 0; ssl->buffers.keySz = 0; ssl->buffers.keyDevId = 0; } #endif #if defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO) || defined(WOLFSSL_HAPROXY) \ || defined(WOLFSSL_NGINX) || defined(WOLFSSL_QT) long wolfSSL_ctrl(WOLFSSL* ssl, int cmd, long opt, void* pt) { WOLFSSL_ENTER("wolfSSL_ctrl"); if (ssl == NULL) return BAD_FUNC_ARG; switch (cmd) { #if defined(WOLFSSL_NGINX) || defined(WOLFSSL_QT) || defined(OPENSSL_ALL) #ifdef HAVE_SNI case SSL_CTRL_SET_TLSEXT_HOSTNAME: WOLFSSL_MSG("Entering Case: SSL_CTRL_SET_TLSEXT_HOSTNAME."); if (pt == NULL) { WOLFSSL_MSG("Passed in NULL Host Name."); break; } return wolfSSL_set_tlsext_host_name(ssl, (const char*) pt); #endif /* HAVE_SNI */ #endif /* WOLFSSL_NGINX || WOLFSSL_QT || OPENSSL_ALL */ default: WOLFSSL_MSG("Case not implemented."); } (void)opt; (void)pt; return WOLFSSL_FAILURE; } long wolfSSL_CTX_ctrl(WOLFSSL_CTX* ctx, int cmd, long opt, void* pt) { #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) long ctrl_opt; #endif long ret = WOLFSSL_SUCCESS; WOLFSSL_ENTER("wolfSSL_CTX_ctrl"); if (ctx == NULL) return WOLFSSL_FAILURE; switch (cmd) { case SSL_CTRL_CHAIN: #ifdef SESSION_CERTS { /* * We don't care about opt here because a copy of the certificate is * stored anyway so increasing the reference counter is not necessary. * Just check to make sure that it is set to one of the correct values. */ WOLF_STACK_OF(WOLFSSL_X509)* sk = (WOLF_STACK_OF(WOLFSSL_X509)*) pt; WOLFSSL_X509* x509; int i; if (opt != 0 && opt != 1) { ret = WOLFSSL_FAILURE; break; } /* Clear certificate chain */ FreeDer(&ctx->certChain); if (sk) { for (i = 0; i < wolfSSL_sk_X509_num(sk); i++) { x509 = wolfSSL_sk_X509_value(sk, i); /* Prevent wolfSSL_CTX_add_extra_chain_cert from freeing cert */ if (wolfSSL_X509_up_ref(x509) != 1) { WOLFSSL_MSG("Error increasing reference count"); continue; } if (wolfSSL_CTX_add_extra_chain_cert(ctx, x509) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("Error adding certificate to context"); /* Decrease reference count on failure */ wolfSSL_X509_free(x509); } } } /* Free previous chain */ wolfSSL_sk_X509_pop_free(ctx->x509Chain, NULL); ctx->x509Chain = sk; if (sk && opt == 1) { /* up all refs when opt == 1 */ for (i = 0; i < wolfSSL_sk_X509_num(sk); i++) { x509 = wolfSSL_sk_X509_value(sk, i); if (wolfSSL_X509_up_ref(x509) != 1) { WOLFSSL_MSG("Error increasing reference count"); continue; } } } } #else WOLFSSL_MSG("Session certificates not compiled in"); ret = WOLFSSL_FAILURE; #endif break; #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) case SSL_CTRL_OPTIONS: WOLFSSL_MSG("Entering Case: SSL_CTRL_OPTIONS."); ctrl_opt = wolfSSL_CTX_set_options(ctx, opt); #ifdef WOLFSSL_QT /* Set whether to use client or server cipher preference */ if ((ctrl_opt & WOLFSSL_OP_CIPHER_SERVER_PREFERENCE) == WOLFSSL_OP_CIPHER_SERVER_PREFERENCE) { WOLFSSL_MSG("Using Server's Cipher Preference."); ctx->useClientOrder = FALSE; } else { WOLFSSL_MSG("Using Client's Cipher Preference."); ctx->useClientOrder = TRUE; } #endif /* WOLFSSL_QT */ return ctrl_opt; #endif /* OPENSSL_EXTRA || HAVE_WEBSERVER */ case SSL_CTRL_EXTRA_CHAIN_CERT: WOLFSSL_MSG("Entering Case: SSL_CTRL_EXTRA_CHAIN_CERT."); if (pt == NULL) { WOLFSSL_MSG("Passed in x509 pointer NULL."); ret = WOLFSSL_FAILURE; break; } return wolfSSL_CTX_add_extra_chain_cert(ctx, (WOLFSSL_X509*)pt); #ifndef NO_DH case SSL_CTRL_SET_TMP_DH: WOLFSSL_MSG("Entering Case: SSL_CTRL_SET_TMP_DH."); if (pt == NULL) { WOLFSSL_MSG("Passed in DH pointer NULL."); ret = WOLFSSL_FAILURE; break; } return wolfSSL_CTX_set_tmp_dh(ctx, (WOLFSSL_DH*)pt); #endif #ifdef HAVE_ECC case SSL_CTRL_SET_TMP_ECDH: WOLFSSL_MSG("Entering Case: SSL_CTRL_SET_TMP_ECDH."); if (pt == NULL) { WOLFSSL_MSG("Passed in ECDH pointer NULL."); ret = WOLFSSL_FAILURE; break; } return wolfSSL_SSL_CTX_set_tmp_ecdh(ctx, (WOLFSSL_EC_KEY*)pt); #endif case SSL_CTRL_MODE: wolfSSL_CTX_set_mode(ctx,opt); break; case SSL_CTRL_SET_MIN_PROTO_VERSION: WOLFSSL_MSG("set min proto version"); return wolfSSL_CTX_set_min_proto_version(ctx, (int)opt); case SSL_CTRL_SET_MAX_PROTO_VERSION: WOLFSSL_MSG("set max proto version"); return wolfSSL_CTX_set_max_proto_version(ctx, (int)opt); case SSL_CTRL_GET_MIN_PROTO_VERSION: WOLFSSL_MSG("get min proto version"); return wolfSSL_CTX_get_min_proto_version(ctx); case SSL_CTRL_GET_MAX_PROTO_VERSION: WOLFSSL_MSG("get max proto version"); return wolfSSL_CTX_get_max_proto_version(ctx); default: WOLFSSL_MSG("CTX_ctrl cmd not implemented"); ret = WOLFSSL_FAILURE; break; } (void)ctx; (void)cmd; (void)opt; (void)pt; WOLFSSL_LEAVE("wolfSSL_CTX_ctrl", (int)ret); return ret; } #ifndef WOLFSSL_NO_STUB long wolfSSL_CTX_callback_ctrl(WOLFSSL_CTX* ctx, int cmd, void (*fp)(void)) { (void) ctx; (void) cmd; (void) fp; WOLFSSL_STUB("wolfSSL_CTX_callback_ctrl"); return WOLFSSL_FAILURE; } #endif /* WOLFSSL_NO_STUB */ #ifndef NO_WOLFSSL_STUB long wolfSSL_CTX_clear_extra_chain_certs(WOLFSSL_CTX* ctx) { return wolfSSL_CTX_ctrl(ctx, SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS, 0L, NULL); } #endif /* Returns the verifyCallback from the ssl structure if successful. Returns NULL otherwise. */ VerifyCallback wolfSSL_get_verify_callback(WOLFSSL* ssl) { WOLFSSL_ENTER("wolfSSL_get_verify_callback()"); if (ssl) { return ssl->verifyCallback; } return NULL; } /* Adds the ASN1 certificate to the user ctx. Returns WOLFSSL_SUCCESS if no error, returns WOLFSSL_FAILURE otherwise.*/ int wolfSSL_CTX_use_certificate_ASN1(WOLFSSL_CTX *ctx, int derSz, const unsigned char *der) { WOLFSSL_ENTER("wolfSSL_CTX_use_certificate_ASN1()"); if (der != NULL && ctx != NULL) { if (wolfSSL_CTX_use_certificate_buffer(ctx, der, derSz, WOLFSSL_FILETYPE_ASN1) == WOLFSSL_SUCCESS) { return WOLFSSL_SUCCESS; } } return WOLFSSL_FAILURE; } #if !defined(HAVE_FAST_RSA) && defined(WOLFSSL_KEY_GEN) && \ !defined(NO_RSA) && !defined(HAVE_USER_RSA) /* Adds the rsa private key to the user ctx. Returns WOLFSSL_SUCCESS if no error, returns WOLFSSL_FAILURE otherwise.*/ int wolfSSL_CTX_use_RSAPrivateKey(WOLFSSL_CTX* ctx, WOLFSSL_RSA* rsa) { int ret; int derSize; unsigned char *maxDerBuf; unsigned char* key = NULL; WOLFSSL_ENTER("wolfSSL_CTX_use_RSAPrivateKey()"); if (ctx == NULL || rsa == NULL) { WOLFSSL_MSG("one or more inputs were NULL"); return BAD_FUNC_ARG; } maxDerBuf = (unsigned char*)XMALLOC(4096, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (maxDerBuf == NULL) { WOLFSSL_MSG("Malloc failure"); return MEMORY_E; } key = maxDerBuf; /* convert RSA struct to der encoded buffer and get the size */ if ((derSize = wolfSSL_i2d_RSAPrivateKey(rsa, &key)) <= 0) { WOLFSSL_MSG("wolfSSL_i2d_RSAPrivateKey() failure"); XFREE(maxDerBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); return WOLFSSL_FAILURE; } ret = wolfSSL_CTX_use_PrivateKey_buffer(ctx, (const unsigned char*)maxDerBuf, derSize, SSL_FILETYPE_ASN1); if (ret != WOLFSSL_SUCCESS) { WOLFSSL_MSG("wolfSSL_CTX_USE_PrivateKey_buffer() failure"); XFREE(maxDerBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); return WOLFSSL_FAILURE; } XFREE(maxDerBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); return ret; } #endif /* NO_RSA && !HAVE_FAST_RSA */ #ifndef NO_BIO /* Converts EVP_PKEY data from a bio buffer to a WOLFSSL_EVP_PKEY structure. Returns pointer to private EVP_PKEY struct upon success, NULL if there is a failure.*/ WOLFSSL_EVP_PKEY* wolfSSL_d2i_PrivateKey_bio(WOLFSSL_BIO* bio, WOLFSSL_EVP_PKEY** out) { unsigned char* mem = NULL; int memSz = 0; WOLFSSL_EVP_PKEY* key = NULL; int i = 0, j = 0; unsigned char* extraBioMem = NULL; int extraBioMemSz = 0; int derLength = 0; WOLFSSL_ENTER("wolfSSL_d2i_PrivateKey_bio()"); if (bio == NULL) { return NULL; } (void)out; memSz = wolfSSL_BIO_get_len(bio); if (memSz <= 0) { WOLFSSL_MSG("wolfSSL_BIO_get_len() failure"); return NULL; } mem = (unsigned char*)XMALLOC(memSz, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); if (mem == NULL) { WOLFSSL_MSG("Malloc failure"); return NULL; } if (wolfSSL_BIO_read(bio, (unsigned char*)mem, memSz) == memSz) { /* Determines key type and returns the new private EVP_PKEY object */ if ((key = wolfSSL_d2i_PrivateKey_EVP(NULL, &mem, (long)memSz)) == NULL) { WOLFSSL_MSG("wolfSSL_d2i_PrivateKey_EVP() failure"); XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); return NULL; } /* Write extra data back into bio object if necessary. */ derLength = key->pkey_sz; extraBioMemSz = (memSz - derLength); if (extraBioMemSz > 0) { extraBioMem = (unsigned char *)XMALLOC(extraBioMemSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (extraBioMem == NULL) { WOLFSSL_MSG("Malloc failure"); XFREE((unsigned char*)extraBioMem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); return NULL; } for (i = derLength; i < memSz; i++) { *(extraBioMem + j) = *(mem + i); j++; } wolfSSL_BIO_write(bio, extraBioMem, extraBioMemSz); if (wolfSSL_BIO_get_len(bio) <= 0) { WOLFSSL_MSG("Failed to write memory to bio"); XFREE((unsigned char*)extraBioMem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); return NULL; } XFREE((unsigned char*)extraBioMem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); } if (out != NULL) { *out = key; } } XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); return key; } #endif /* !NO_BIO */ #endif /* OPENSSL_ALL || WOLFSSL_ASIO || WOLFSSL_HAPROXY || WOLFSSL_QT */ #if defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO) || defined(WOLFSSL_HAPROXY) || \ defined(WOLFSSL_NGINX) || defined(WOLFSSL_QT) || defined(WOLFSSL_WPAS_SMALL) /* Converts a DER encoded private key to a WOLFSSL_EVP_PKEY structure. * returns a pointer to a new WOLFSSL_EVP_PKEY structure on success and NULL * on fail */ WOLFSSL_EVP_PKEY* wolfSSL_d2i_PrivateKey_EVP(WOLFSSL_EVP_PKEY** out, unsigned char** in, long inSz) { WOLFSSL_ENTER("wolfSSL_d2i_PrivateKey_EVP"); return d2iGenericKey(out, (const unsigned char**)in, inSz, 1); } #endif /* OPENSSL_ALL || WOLFSSL_ASIO || WOLFSSL_HAPROXY || WOLFSSL_QT || WOLFSSL_WPAS_SMALL*/ /* stunnel compatibility functions*/ #if defined(OPENSSL_ALL) || (defined(OPENSSL_EXTRA) && (defined(HAVE_STUNNEL) || \ defined(WOLFSSL_NGINX) || defined(HAVE_LIGHTY) || \ defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_OPENSSH))) void wolfSSL_ERR_remove_thread_state(void* pid) { (void) pid; return; } #ifndef NO_FILESYSTEM /***TBD ***/ void wolfSSL_print_all_errors_fp(XFILE fp) { (void)fp; } #endif /* !NO_FILESYSTEM */ #endif /* OPENSSL_ALL || OPENSSL_EXTRA || HAVE_STUNNEL || WOLFSSL_NGINX || HAVE_LIGHTY || WOLFSSL_HAPROXY || WOLFSSL_OPENSSH */ #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) || \ defined(HAVE_EX_DATA) #if defined(HAVE_EX_DATA) && !defined(NO_SESSION_CACHE) static void SESSION_ex_data_cache_update(WOLFSSL_SESSION* session, int idx, void* data, byte get, void** getRet, int* setRet) { int row; int i; int error = 0; SessionRow* sessRow = NULL; const byte* id; byte foundCache = 0; if (getRet != NULL) *getRet = NULL; if (setRet != NULL) *setRet = WOLFSSL_FAILURE; id = session->sessionID; if (session->haveAltSessionID) id = session->altSessionID; row = (int)(HashSession(id, ID_LEN, &error) % SESSION_ROWS); if (error != 0) { WOLFSSL_MSG("Hash session failed"); return; } sessRow = &SessionCache[row]; if (SESSION_ROW_LOCK(sessRow) != 0) { WOLFSSL_MSG("Session row lock failed"); return; } for (i = 0; i < SESSIONS_PER_ROW && i < sessRow->totalCount; i++) { if (XMEMCMP(id, sessRow->Sessions[i].sessionID, ID_LEN) == 0 && session->side == sessRow->Sessions[i].side) { if (get) { *getRet = wolfSSL_CRYPTO_get_ex_data( &sessRow->Sessions[i].ex_data, idx); } else { *setRet = wolfSSL_CRYPTO_set_ex_data( &sessRow->Sessions[i].ex_data, idx, data); } foundCache = 1; break; } } SESSION_ROW_UNLOCK(sessRow); /* If we don't have a session in cache then clear the ex_data and * own it */ if (!foundCache) { XMEMSET(&session->ex_data, 0, sizeof(WOLFSSL_CRYPTO_EX_DATA)); session->ownExData = 1; if (!get) { *setRet = wolfSSL_CRYPTO_set_ex_data(&session->ex_data, idx, data); } } } #endif int wolfSSL_SESSION_set_ex_data(WOLFSSL_SESSION* session, int idx, void* data) { int ret = WOLFSSL_FAILURE; WOLFSSL_ENTER("wolfSSL_SESSION_set_ex_data"); #ifdef HAVE_EX_DATA session = ClientSessionToSession(session); if (session != NULL) { #ifndef NO_SESSION_CACHE if (!session->ownExData) { /* Need to update in cache */ SESSION_ex_data_cache_update(session, idx, data, 0, NULL, &ret); } else #endif { ret = wolfSSL_CRYPTO_set_ex_data(&session->ex_data, idx, data); } } #else (void)session; (void)idx; (void)data; #endif return ret; } #ifdef HAVE_EX_DATA_CLEANUP_HOOKS int wolfSSL_SESSION_set_ex_data_with_cleanup( WOLFSSL_SESSION* session, int idx, void* data, wolfSSL_ex_data_cleanup_routine_t cleanup_routine) { WOLFSSL_ENTER("wolfSSL_SESSION_set_ex_data_with_cleanup"); session = ClientSessionToSession(session); if(session != NULL) { return wolfSSL_CRYPTO_set_ex_data_with_cleanup(&session->ex_data, idx, data, cleanup_routine); } return WOLFSSL_FAILURE; } #endif /* HAVE_EX_DATA_CLEANUP_HOOKS */ void* wolfSSL_SESSION_get_ex_data(const WOLFSSL_SESSION* session, int idx) { void* ret = NULL; WOLFSSL_ENTER("wolfSSL_SESSION_get_ex_data"); #ifdef HAVE_EX_DATA session = ClientSessionToSession(session); if (session != NULL) { #ifndef NO_SESSION_CACHE if (!session->ownExData) { /* Need to retrieve the data from the session cache */ SESSION_ex_data_cache_update((WOLFSSL_SESSION*)session, idx, NULL, 1, &ret, NULL); } else #endif { ret = wolfSSL_CRYPTO_get_ex_data(&session->ex_data, idx); } } #else (void)session; (void)idx; #endif return ret; } #endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL || HAVE_EX_DATA */ /* Note: This is a huge section of API's - through * wolfSSL_X509_OBJECT_get0_X509_CRL */ #if defined(OPENSSL_ALL) || (defined(OPENSSL_EXTRA) && \ (defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || \ defined(HAVE_LIGHTY) || defined(WOLFSSL_HAPROXY) || \ defined(WOLFSSL_OPENSSH) || defined(HAVE_SBLIM_SFCB))) #ifdef HAVE_EX_DATA int wolfSSL_SESSION_get_ex_new_index(long idx, void* data, void* cb1, void* cb2, CRYPTO_free_func* cb3) { WOLFSSL_ENTER("wolfSSL_SESSION_get_ex_new_index"); (void)idx; (void)cb1; (void)cb2; (void)cb3; (void)data; return wolfssl_get_ex_new_index(WOLF_CRYPTO_EX_INDEX_SSL_SESSION); } #endif #if defined(USE_WOLFSSL_MEMORY) && !defined(WOLFSSL_DEBUG_MEMORY) static wolfSSL_OSSL_Malloc_cb ossl_malloc = NULL; static wolfSSL_OSSL_Free_cb ossl_free = NULL; static wolfSSL_OSSL_Realloc_cb ossl_realloc = NULL; static void* OSSL_Malloc(size_t size) { if (ossl_malloc != NULL) return ossl_malloc(size, NULL, 0); else return NULL; } static void OSSL_Free(void *ptr) { if (ossl_free != NULL) ossl_free(ptr, NULL, 0); } static void* OSSL_Realloc(void *ptr, size_t size) { if (ossl_realloc != NULL) return ossl_realloc(ptr, size, NULL, 0); else return NULL; } #endif /* USE_WOLFSSL_MEMORY && !WOLFSSL_DEBUG_MEMORY */ int wolfSSL_CRYPTO_set_mem_functions( wolfSSL_OSSL_Malloc_cb m, wolfSSL_OSSL_Realloc_cb r, wolfSSL_OSSL_Free_cb f) { #ifdef USE_WOLFSSL_MEMORY #ifdef WOLFSSL_DEBUG_MEMORY WOLFSSL_MSG("mem functions will receive function name instead of " "file name"); if (wolfSSL_SetAllocators((wolfSSL_Malloc_cb)m, (wolfSSL_Free_cb)f, (wolfSSL_Realloc_cb)r) == 0) return WOLFSSL_SUCCESS; #else WOLFSSL_MSG("wolfSSL was compiled without WOLFSSL_DEBUG_MEMORY. mem " "functions will receive a NULL file name and 0 for the " "line number."); if (wolfSSL_SetAllocators(OSSL_Malloc, OSSL_Free, OSSL_Realloc) == 0) { ossl_malloc = m; ossl_free = f; ossl_realloc = r; return WOLFSSL_SUCCESS; } #endif else return WOLFSSL_FAILURE; #else (void)m; (void)r; (void)f; WOLFSSL_MSG("wolfSSL allocator callback functions not compiled in"); return WOLFSSL_FAILURE; #endif } int wolfSSL_ERR_load_ERR_strings(void) { return WOLFSSL_SUCCESS; } void wolfSSL_ERR_load_crypto_strings(void) { WOLFSSL_ENTER("wolfSSL_ERR_load_crypto_strings"); /* Do nothing */ return; } int wolfSSL_FIPS_mode(void) { #ifdef HAVE_FIPS return 1; #else return 0; #endif } int wolfSSL_FIPS_mode_set(int r) { #ifdef HAVE_FIPS if (r == 0) { WOLFSSL_MSG("Cannot disable FIPS at runtime."); return WOLFSSL_FAILURE; } return WOLFSSL_SUCCESS; #else if (r == 0) { return WOLFSSL_SUCCESS; } WOLFSSL_MSG("Cannot enable FIPS. This isn't the wolfSSL FIPS code."); return WOLFSSL_FAILURE; #endif } int wolfSSL_CIPHER_get_bits(const WOLFSSL_CIPHER *c, int *alg_bits) { int ret = WOLFSSL_FAILURE; WOLFSSL_ENTER("wolfSSL_CIPHER_get_bits"); #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) (void)alg_bits; if (c!= NULL) ret = c->bits; #else if (c != NULL && c->ssl != NULL) { ret = 8 * c->ssl->specs.key_size; if (alg_bits != NULL) { *alg_bits = ret; } } #endif return ret; } /* returns value less than 0 on fail to match * On a successful match the priority level found is returned */ int wolfSSL_sk_SSL_CIPHER_find( WOLF_STACK_OF(WOLFSSL_CIPHER)* sk, const WOLFSSL_CIPHER* toFind) { WOLFSSL_STACK* next; int i, sz; if (sk == NULL || toFind == NULL) { return WOLFSSL_FATAL_ERROR; } sz = wolfSSL_sk_SSL_CIPHER_num(sk); next = sk; for (i = 0; i < sz && next != NULL; i++) { if (next->data.cipher.cipherSuite0 == toFind->cipherSuite0 && next->data.cipher.cipherSuite == toFind->cipherSuite) { return sz - i; /* reverse because stack pushed highest on first */ } next = next->next; } return WOLFSSL_FATAL_ERROR; } /* free's all nodes in the stack and there data */ void wolfSSL_sk_SSL_CIPHER_free(WOLF_STACK_OF(WOLFSSL_CIPHER)* sk) { WOLFSSL_ENTER("wolfSSL_sk_SSL_CIPHER_free"); wolfSSL_sk_free(sk); } #ifdef HAVE_SNI int wolfSSL_set_tlsext_host_name(WOLFSSL* ssl, const char* host_name) { int ret; WOLFSSL_ENTER("wolfSSL_set_tlsext_host_name"); ret = wolfSSL_UseSNI(ssl, WOLFSSL_SNI_HOST_NAME, host_name, (word16)XSTRLEN(host_name)); WOLFSSL_LEAVE("wolfSSL_set_tlsext_host_name", ret); return ret; } #ifndef NO_WOLFSSL_SERVER const char * wolfSSL_get_servername(WOLFSSL* ssl, byte type) { void * serverName = NULL; if (ssl == NULL) return NULL; TLSX_SNI_GetRequest(ssl->extensions, type, &serverName); return (const char *)serverName; } #endif /* NO_WOLFSSL_SERVER */ #endif /* HAVE_SNI */ WOLFSSL_CTX* wolfSSL_set_SSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx) { if (ssl && ctx && SetSSL_CTX(ssl, ctx, 0) == WOLFSSL_SUCCESS) return ssl->ctx; return NULL; } VerifyCallback wolfSSL_CTX_get_verify_callback(WOLFSSL_CTX* ctx) { WOLFSSL_ENTER("wolfSSL_CTX_get_verify_callback"); if(ctx) return ctx->verifyCallback; return NULL; } #ifdef HAVE_SNI void wolfSSL_CTX_set_servername_callback(WOLFSSL_CTX* ctx, CallbackSniRecv cb) { WOLFSSL_ENTER("wolfSSL_CTX_set_servername_callback"); if (ctx) ctx->sniRecvCb = cb; } int wolfSSL_CTX_set_tlsext_servername_callback(WOLFSSL_CTX* ctx, CallbackSniRecv cb) { WOLFSSL_ENTER("wolfSSL_CTX_set_tlsext_servername_callback"); if (ctx) { ctx->sniRecvCb = cb; return WOLFSSL_SUCCESS; } return WOLFSSL_FAILURE; } int wolfSSL_CTX_set_servername_arg(WOLFSSL_CTX* ctx, void* arg) { WOLFSSL_ENTER("wolfSSL_CTX_set_servername_arg"); if (ctx) { ctx->sniRecvCbArg = arg; return WOLFSSL_SUCCESS; } return WOLFSSL_FAILURE; } #endif /* HAVE_SNI */ #ifndef NO_BIO void wolfSSL_ERR_load_BIO_strings(void) { WOLFSSL_ENTER("ERR_load_BIO_strings"); /* do nothing */ } #endif #ifndef NO_WOLFSSL_STUB /* Set THREADID callback, return 1 on success, 0 on error */ int wolfSSL_THREADID_set_callback( void(*threadid_func)(WOLFSSL_CRYPTO_THREADID*)) { WOLFSSL_ENTER("wolfSSL_THREADID_set_callback"); WOLFSSL_STUB("CRYPTO_THREADID_set_callback"); (void)threadid_func; return 1; } #endif #ifndef NO_WOLFSSL_STUB void wolfSSL_THREADID_set_numeric(void* id, unsigned long val) { WOLFSSL_ENTER("wolfSSL_THREADID_set_numeric"); WOLFSSL_STUB("CRYPTO_THREADID_set_numeric"); (void)id; (void)val; return; } #endif #endif /* OPENSSL_ALL || (OPENSSL_EXTRA && (HAVE_STUNNEL || WOLFSSL_NGINX || * HAVE_LIGHTY || WOLFSSL_HAPROXY || WOLFSSL_OPENSSH || * HAVE_SBLIM_SFCB)) */ #if defined(OPENSSL_EXTRA) int wolfSSL_CRYPTO_memcmp(const void *a, const void *b, size_t size) { if (!a || !b) return 0; return ConstantCompare((const byte*)a, (const byte*)b, (int)size); } unsigned long wolfSSL_ERR_peek_last_error(void) { WOLFSSL_ENTER("wolfSSL_ERR_peek_last_error"); #ifdef WOLFSSL_HAVE_ERROR_QUEUE { int ret; if ((ret = wc_PeekErrorNode(-1, NULL, NULL, NULL)) < 0) { WOLFSSL_MSG("Issue peeking at error node in queue"); return 0; } if (ret == -ASN_NO_PEM_HEADER) return (ERR_LIB_PEM << 24) | PEM_R_NO_START_LINE; #if defined(WOLFSSL_PYTHON) if (ret == ASN1_R_HEADER_TOO_LONG) return (ERR_LIB_ASN1 << 24) | ASN1_R_HEADER_TOO_LONG; #endif return (unsigned long)ret; } #else return (unsigned long)(0 - NOT_COMPILED_IN); #endif } #endif /* OPENSSL_EXTRA */ int wolfSSL_version(WOLFSSL* ssl) { WOLFSSL_ENTER("wolfSSL_version"); if (ssl->version.major == SSLv3_MAJOR) { switch (ssl->version.minor) { case SSLv3_MINOR : return SSL3_VERSION; case TLSv1_MINOR : return TLS1_VERSION; case TLSv1_1_MINOR : return TLS1_1_VERSION; case TLSv1_2_MINOR : return TLS1_2_VERSION; case TLSv1_3_MINOR : return TLS1_3_VERSION; default: return WOLFSSL_FAILURE; } } else if (ssl->version.major == DTLS_MAJOR) { switch (ssl->version.minor) { case DTLS_MINOR : return DTLS1_VERSION; case DTLSv1_2_MINOR : return DTLS1_2_VERSION; default: return WOLFSSL_FAILURE; } } return WOLFSSL_FAILURE; } WOLFSSL_CTX* wolfSSL_get_SSL_CTX(WOLFSSL* ssl) { WOLFSSL_ENTER("wolfSSL_get_SSL_CTX"); return ssl->ctx; } #if defined(OPENSSL_ALL) || \ defined(OPENSSL_EXTRA) || defined(HAVE_STUNNEL) || \ defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) const byte* wolfSSL_SESSION_get_id(const WOLFSSL_SESSION* sess, unsigned int* idLen) { WOLFSSL_ENTER("wolfSSL_SESSION_get_id"); sess = ClientSessionToSession(sess); if (sess == NULL || idLen == NULL) { WOLFSSL_MSG("Bad func args. Please provide idLen"); return NULL; } *idLen = sess->sessionIDSz; return sess->sessionID; } #if (defined(HAVE_SESSION_TICKET) || defined(SESSION_CERTS)) && \ !defined(NO_FILESYSTEM) #ifndef NO_BIO #if defined(SESSION_CERTS) || \ (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) /* returns a pointer to the protocol used by the session */ static const char* wolfSSL_SESSION_get_protocol(const WOLFSSL_SESSION* in) { in = ClientSessionToSession(in); return wolfSSL_internal_get_version((ProtocolVersion*)&in->version); } #endif /* returns true (non 0) if the session has EMS (extended master secret) */ static int wolfSSL_SESSION_haveEMS(const WOLFSSL_SESSION* in) { in = ClientSessionToSession(in); if (in == NULL) return 0; return in->haveEMS; } #if defined(HAVE_SESSION_TICKET) /* prints out the ticket to bio passed in * return WOLFSSL_SUCCESS on success */ static int wolfSSL_SESSION_print_ticket(WOLFSSL_BIO* bio, const WOLFSSL_SESSION* in, const char* tab) { unsigned short i, j, z, sz; short tag = 0; byte* pt; in = ClientSessionToSession(in); if (in == NULL || bio == NULL) { return BAD_FUNC_ARG; } sz = in->ticketLen; pt = in->ticket; if (wolfSSL_BIO_printf(bio, "%s\n", (sz == 0)? " NONE": "") <= 0) return WOLFSSL_FAILURE; for (i = 0; i < sz;) { char asc[16]; if (sz - i < 16) { if (wolfSSL_BIO_printf(bio, "%s%04X -", tab, tag + (sz - i)) <= 0) return WOLFSSL_FAILURE; } else { if (wolfSSL_BIO_printf(bio, "%s%04X -", tab, tag) <= 0) return WOLFSSL_FAILURE; } for (j = 0; i < sz && j < 8; j++,i++) { asc[j] = ((pt[i])&0x6f)>='A'?((pt[i])&0x6f):'.'; if (wolfSSL_BIO_printf(bio, " %02X", pt[i]) <= 0) return WOLFSSL_FAILURE; } if (i < sz) { asc[j] = ((pt[i])&0x6f)>='A'?((pt[i])&0x6f):'.'; if (wolfSSL_BIO_printf(bio, "-%02X", pt[i]) <= 0) return WOLFSSL_FAILURE; j++; i++; } for (; i < sz && j < 16; j++,i++) { asc[j] = ((pt[i])&0x6f)>='A'?((pt[i])&0x6f):'.'; if (wolfSSL_BIO_printf(bio, " %02X", pt[i]) <= 0) return WOLFSSL_FAILURE; } /* pad out spacing */ for (z = j; z < 17; z++) { if (wolfSSL_BIO_printf(bio, " ") <= 0) return WOLFSSL_FAILURE; } for (z = 0; z < j; z++) { if (wolfSSL_BIO_printf(bio, "%c", asc[z]) <= 0) return WOLFSSL_FAILURE; } if (wolfSSL_BIO_printf(bio, "\n") <= 0) return WOLFSSL_FAILURE; tag += 16; } return WOLFSSL_SUCCESS; } #endif /* HAVE_SESSION_TICKET */ /* prints out the session information in human readable form * return WOLFSSL_SUCCESS on success */ int wolfSSL_SESSION_print(WOLFSSL_BIO *bp, const WOLFSSL_SESSION *session) { const unsigned char* pt; unsigned char buf[SECRET_LEN]; unsigned int sz = 0, i; int ret; session = ClientSessionToSession(session); if (session == NULL) { return WOLFSSL_FAILURE; } if (wolfSSL_BIO_printf(bp, "%s\n", "SSL-Session:") <= 0) return WOLFSSL_FAILURE; #if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \ defined(HAVE_SESSION_TICKET)) if (wolfSSL_BIO_printf(bp, " Protocol : %s\n", wolfSSL_SESSION_get_protocol(session)) <= 0) return WOLFSSL_FAILURE; #endif if (wolfSSL_BIO_printf(bp, " Cipher : %s\n", wolfSSL_SESSION_CIPHER_get_name(session)) <= 0) return WOLFSSL_FAILURE; pt = wolfSSL_SESSION_get_id(session, &sz); if (wolfSSL_BIO_printf(bp, " Session-ID: ") <= 0) return WOLFSSL_FAILURE; for (i = 0; i < sz; i++) { if (wolfSSL_BIO_printf(bp, "%02X", pt[i]) <= 0) return WOLFSSL_FAILURE; } if (wolfSSL_BIO_printf(bp, "\n") <= 0) return WOLFSSL_FAILURE; if (wolfSSL_BIO_printf(bp, " Session-ID-ctx: \n") <= 0) return WOLFSSL_FAILURE; ret = wolfSSL_SESSION_get_master_key(session, buf, sizeof(buf)); if (wolfSSL_BIO_printf(bp, " Master-Key: ") <= 0) return WOLFSSL_FAILURE; if (ret > 0) { sz = (unsigned int)ret; for (i = 0; i < sz; i++) { if (wolfSSL_BIO_printf(bp, "%02X", buf[i]) <= 0) return WOLFSSL_FAILURE; } } if (wolfSSL_BIO_printf(bp, "\n") <= 0) return WOLFSSL_FAILURE; /* @TODO PSK identity hint and SRP */ if (wolfSSL_BIO_printf(bp, " TLS session ticket:") <= 0) return WOLFSSL_FAILURE; #ifdef HAVE_SESSION_TICKET if (wolfSSL_SESSION_print_ticket(bp, session, " ") != WOLFSSL_SUCCESS) return WOLFSSL_FAILURE; #endif #if !defined(NO_SESSION_CACHE) && (defined(OPENSSL_EXTRA) || \ defined(HAVE_EXT_CACHE)) if (wolfSSL_BIO_printf(bp, " Start Time: %ld\n", wolfSSL_SESSION_get_time(session)) <= 0) return WOLFSSL_FAILURE; if (wolfSSL_BIO_printf(bp, " Timeout : %ld (sec)\n", wolfSSL_SESSION_get_timeout(session)) <= 0) return WOLFSSL_FAILURE; #endif /* !NO_SESSION_CACHE && OPENSSL_EXTRA || HAVE_EXT_CACHE */ /* @TODO verify return code print */ if (wolfSSL_BIO_printf(bp, " Extended master secret: %s\n", (wolfSSL_SESSION_haveEMS(session) == 0)? "no" : "yes") <= 0) return WOLFSSL_FAILURE; return WOLFSSL_SUCCESS; } #endif /* !NO_BIO */ #endif /* (HAVE_SESSION_TICKET || SESSION_CERTS) && !NO_FILESYSTEM */ #endif /* OPENSSL_ALL || OPENSSL_EXTRA || HAVE_STUNNEL || WOLFSSL_NGINX || WOLFSSL_HAPROXY */ #if defined(OPENSSL_ALL) || (defined(OPENSSL_EXTRA) && defined(HAVE_STUNNEL)) \ || defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(WOLFSSL_NGINX) /* TODO: Doesn't currently track SSL_VERIFY_CLIENT_ONCE */ int wolfSSL_get_verify_mode(const WOLFSSL* ssl) { int mode = 0; WOLFSSL_ENTER("wolfSSL_get_verify_mode"); if (!ssl) { return WOLFSSL_FAILURE; } if (ssl->options.verifyNone) { mode = WOLFSSL_VERIFY_NONE; } else { if (ssl->options.verifyPeer) { mode |= WOLFSSL_VERIFY_PEER; } if (ssl->options.failNoCert) { mode |= WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT; } if (ssl->options.failNoCertxPSK) { mode |= WOLFSSL_VERIFY_FAIL_EXCEPT_PSK; } #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) if (ssl->options.verifyPostHandshake) { mode |= WOLFSSL_VERIFY_POST_HANDSHAKE; } #endif } WOLFSSL_LEAVE("wolfSSL_get_verify_mode", mode); return mode; } int wolfSSL_CTX_get_verify_mode(const WOLFSSL_CTX* ctx) { int mode = 0; WOLFSSL_ENTER("wolfSSL_CTX_get_verify_mode"); if (!ctx) { return WOLFSSL_FAILURE; } if (ctx->verifyNone) { mode = WOLFSSL_VERIFY_NONE; } else { if (ctx->verifyPeer) { mode |= WOLFSSL_VERIFY_PEER; } if (ctx->failNoCert) { mode |= WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT; } if (ctx->failNoCertxPSK) { mode |= WOLFSSL_VERIFY_FAIL_EXCEPT_PSK; } #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) if (ctx->verifyPostHandshake) { mode |= WOLFSSL_VERIFY_POST_HANDSHAKE; } #endif } WOLFSSL_LEAVE("wolfSSL_CTX_get_verify_mode", mode); return mode; } #endif #if defined(OPENSSL_EXTRA) && defined(HAVE_CURVE25519) /* return 1 if success, 0 if error * output keys are little endian format */ int wolfSSL_EC25519_generate_key(unsigned char *priv, unsigned int *privSz, unsigned char *pub, unsigned int *pubSz) { #ifndef WOLFSSL_KEY_GEN WOLFSSL_MSG("No Key Gen built in"); (void) priv; (void) privSz; (void) pub; (void) pubSz; return WOLFSSL_FAILURE; #else /* WOLFSSL_KEY_GEN */ int ret = WOLFSSL_FAILURE; int initTmpRng = 0; WC_RNG *rng = NULL; #ifdef WOLFSSL_SMALL_STACK WC_RNG *tmpRNG = NULL; #else WC_RNG tmpRNG[1]; #endif WOLFSSL_ENTER("wolfSSL_EC25519_generate_key"); if (priv == NULL || privSz == NULL || *privSz < CURVE25519_KEYSIZE || pub == NULL || pubSz == NULL || *pubSz < CURVE25519_KEYSIZE) { WOLFSSL_MSG("Bad arguments"); return WOLFSSL_FAILURE; } #ifdef WOLFSSL_SMALL_STACK tmpRNG = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG); if (tmpRNG == NULL) return WOLFSSL_FAILURE; #endif if (wc_InitRng(tmpRNG) == 0) { rng = tmpRNG; initTmpRng = 1; } else { WOLFSSL_MSG("Bad RNG Init, trying global"); if (initGlobalRNG == 0) WOLFSSL_MSG("Global RNG no Init"); else rng = &globalRNG; } if (rng) { curve25519_key key; if (wc_curve25519_init(&key) != MP_OKAY) WOLFSSL_MSG("wc_curve25519_init failed"); else if (wc_curve25519_make_key(rng, CURVE25519_KEYSIZE, &key)!=MP_OKAY) WOLFSSL_MSG("wc_curve25519_make_key failed"); /* export key pair */ else if (wc_curve25519_export_key_raw_ex(&key, priv, privSz, pub, pubSz, EC25519_LITTLE_ENDIAN) != MP_OKAY) WOLFSSL_MSG("wc_curve25519_export_key_raw_ex failed"); else ret = WOLFSSL_SUCCESS; wc_curve25519_free(&key); } if (initTmpRng) wc_FreeRng(tmpRNG); #ifdef WOLFSSL_SMALL_STACK XFREE(tmpRNG, NULL, DYNAMIC_TYPE_RNG); #endif return ret; #endif /* WOLFSSL_KEY_GEN */ } /* return 1 if success, 0 if error * input and output keys are little endian format */ int wolfSSL_EC25519_shared_key(unsigned char *shared, unsigned int *sharedSz, const unsigned char *priv, unsigned int privSz, const unsigned char *pub, unsigned int pubSz) { #ifndef WOLFSSL_KEY_GEN WOLFSSL_MSG("No Key Gen built in"); (void) shared; (void) sharedSz; (void) priv; (void) privSz; (void) pub; (void) pubSz; return WOLFSSL_FAILURE; #else /* WOLFSSL_KEY_GEN */ int ret = WOLFSSL_FAILURE; curve25519_key privkey, pubkey; WOLFSSL_ENTER("wolfSSL_EC25519_shared_key"); if (shared == NULL || sharedSz == NULL || *sharedSz < CURVE25519_KEYSIZE || priv == NULL || privSz < CURVE25519_KEYSIZE || pub == NULL || pubSz < CURVE25519_KEYSIZE) { WOLFSSL_MSG("Bad arguments"); return WOLFSSL_FAILURE; } /* import private key */ if (wc_curve25519_init(&privkey) != MP_OKAY) { WOLFSSL_MSG("wc_curve25519_init privkey failed"); return ret; } if (wc_curve25519_import_private_ex(priv, privSz, &privkey, EC25519_LITTLE_ENDIAN) != MP_OKAY) { WOLFSSL_MSG("wc_curve25519_import_private_ex failed"); wc_curve25519_free(&privkey); return ret; } /* import public key */ if (wc_curve25519_init(&pubkey) != MP_OKAY) { WOLFSSL_MSG("wc_curve25519_init pubkey failed"); wc_curve25519_free(&privkey); return ret; } if (wc_curve25519_import_public_ex(pub, pubSz, &pubkey, EC25519_LITTLE_ENDIAN) != MP_OKAY) { WOLFSSL_MSG("wc_curve25519_import_public_ex failed"); wc_curve25519_free(&privkey); wc_curve25519_free(&pubkey); return ret; } if (wc_curve25519_shared_secret_ex(&privkey, &pubkey, shared, sharedSz, EC25519_LITTLE_ENDIAN) != MP_OKAY) WOLFSSL_MSG("wc_curve25519_shared_secret_ex failed"); else ret = WOLFSSL_SUCCESS; wc_curve25519_free(&privkey); wc_curve25519_free(&pubkey); return ret; #endif /* WOLFSSL_KEY_GEN */ } #endif /* OPENSSL_EXTRA && HAVE_CURVE25519 */ #if defined(OPENSSL_EXTRA) && defined(HAVE_ED25519) /* return 1 if success, 0 if error * output keys are little endian format */ int wolfSSL_ED25519_generate_key(unsigned char *priv, unsigned int *privSz, unsigned char *pub, unsigned int *pubSz) { #ifndef WOLFSSL_KEY_GEN WOLFSSL_MSG("No Key Gen built in"); (void) priv; (void) privSz; (void) pub; (void) pubSz; return WOLFSSL_FAILURE; #elif !defined(HAVE_ED25519_KEY_EXPORT) WOLFSSL_MSG("No ED25519 key export built in"); (void) priv; (void) privSz; (void) pub; (void) pubSz; return WOLFSSL_FAILURE; #else /* WOLFSSL_KEY_GEN && HAVE_ED25519_KEY_EXPORT */ int ret = WOLFSSL_FAILURE; int initTmpRng = 0; WC_RNG *rng = NULL; #ifdef WOLFSSL_SMALL_STACK WC_RNG *tmpRNG = NULL; #else WC_RNG tmpRNG[1]; #endif WOLFSSL_ENTER("wolfSSL_ED25519_generate_key"); if (priv == NULL || privSz == NULL || *privSz < ED25519_PRV_KEY_SIZE || pub == NULL || pubSz == NULL || *pubSz < ED25519_PUB_KEY_SIZE) { WOLFSSL_MSG("Bad arguments"); return WOLFSSL_FAILURE; } #ifdef WOLFSSL_SMALL_STACK tmpRNG = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG); if (tmpRNG == NULL) return WOLFSSL_FATAL_ERROR; #endif if (wc_InitRng(tmpRNG) == 0) { rng = tmpRNG; initTmpRng = 1; } else { WOLFSSL_MSG("Bad RNG Init, trying global"); if (initGlobalRNG == 0) WOLFSSL_MSG("Global RNG no Init"); else rng = &globalRNG; } if (rng) { ed25519_key key; if (wc_ed25519_init(&key) != MP_OKAY) WOLFSSL_MSG("wc_ed25519_init failed"); else if (wc_ed25519_make_key(rng, ED25519_KEY_SIZE, &key)!=MP_OKAY) WOLFSSL_MSG("wc_ed25519_make_key failed"); /* export private key */ else if (wc_ed25519_export_key(&key, priv, privSz, pub, pubSz)!=MP_OKAY) WOLFSSL_MSG("wc_ed25519_export_key failed"); else ret = WOLFSSL_SUCCESS; wc_ed25519_free(&key); } if (initTmpRng) wc_FreeRng(tmpRNG); #ifdef WOLFSSL_SMALL_STACK XFREE(tmpRNG, NULL, DYNAMIC_TYPE_RNG); #endif return ret; #endif /* WOLFSSL_KEY_GEN && HAVE_ED25519_KEY_EXPORT */ } /* return 1 if success, 0 if error * input and output keys are little endian format * priv is a buffer containing private and public part of key */ int wolfSSL_ED25519_sign(const unsigned char *msg, unsigned int msgSz, const unsigned char *priv, unsigned int privSz, unsigned char *sig, unsigned int *sigSz) { #if !defined(HAVE_ED25519_SIGN) || !defined(WOLFSSL_KEY_GEN) || !defined(HAVE_ED25519_KEY_IMPORT) #if !defined(HAVE_ED25519_SIGN) WOLFSSL_MSG("No ED25519 sign built in"); #elif !defined(WOLFSSL_KEY_GEN) WOLFSSL_MSG("No Key Gen built in"); #elif !defined(HAVE_ED25519_KEY_IMPORT) WOLFSSL_MSG("No ED25519 Key import built in"); #endif (void) msg; (void) msgSz; (void) priv; (void) privSz; (void) sig; (void) sigSz; return WOLFSSL_FAILURE; #else /* HAVE_ED25519_SIGN && WOLFSSL_KEY_GEN && HAVE_ED25519_KEY_IMPORT */ ed25519_key key; int ret = WOLFSSL_FAILURE; WOLFSSL_ENTER("wolfSSL_ED25519_sign"); if (priv == NULL || privSz != ED25519_PRV_KEY_SIZE || msg == NULL || sig == NULL || *sigSz < ED25519_SIG_SIZE) { WOLFSSL_MSG("Bad arguments"); return WOLFSSL_FAILURE; } /* import key */ if (wc_ed25519_init(&key) != MP_OKAY) { WOLFSSL_MSG("wc_curve25519_init failed"); return ret; } if (wc_ed25519_import_private_key(priv, privSz/2, priv+(privSz/2), ED25519_PUB_KEY_SIZE, &key) != MP_OKAY){ WOLFSSL_MSG("wc_ed25519_import_private failed"); wc_ed25519_free(&key); return ret; } if (wc_ed25519_sign_msg(msg, msgSz, sig, sigSz, &key) != MP_OKAY) WOLFSSL_MSG("wc_curve25519_shared_secret_ex failed"); else ret = WOLFSSL_SUCCESS; wc_ed25519_free(&key); return ret; #endif /* HAVE_ED25519_SIGN && WOLFSSL_KEY_GEN && HAVE_ED25519_KEY_IMPORT */ } /* return 1 if success, 0 if error * input and output keys are little endian format * pub is a buffer containing public part of key */ int wolfSSL_ED25519_verify(const unsigned char *msg, unsigned int msgSz, const unsigned char *pub, unsigned int pubSz, const unsigned char *sig, unsigned int sigSz) { #if !defined(HAVE_ED25519_VERIFY) || !defined(WOLFSSL_KEY_GEN) || !defined(HAVE_ED25519_KEY_IMPORT) #if !defined(HAVE_ED25519_VERIFY) WOLFSSL_MSG("No ED25519 verify built in"); #elif !defined(WOLFSSL_KEY_GEN) WOLFSSL_MSG("No Key Gen built in"); #elif !defined(HAVE_ED25519_KEY_IMPORT) WOLFSSL_MSG("No ED25519 Key import built in"); #endif (void) msg; (void) msgSz; (void) pub; (void) pubSz; (void) sig; (void) sigSz; return WOLFSSL_FAILURE; #else /* HAVE_ED25519_VERIFY && WOLFSSL_KEY_GEN && HAVE_ED25519_KEY_IMPORT */ ed25519_key key; int ret = WOLFSSL_FAILURE, check = 0; WOLFSSL_ENTER("wolfSSL_ED25519_verify"); if (pub == NULL || pubSz != ED25519_PUB_KEY_SIZE || msg == NULL || sig == NULL || sigSz != ED25519_SIG_SIZE) { WOLFSSL_MSG("Bad arguments"); return WOLFSSL_FAILURE; } /* import key */ if (wc_ed25519_init(&key) != MP_OKAY) { WOLFSSL_MSG("wc_curve25519_init failed"); return ret; } if (wc_ed25519_import_public(pub, pubSz, &key) != MP_OKAY){ WOLFSSL_MSG("wc_ed25519_import_public failed"); wc_ed25519_free(&key); return ret; } if ((ret = wc_ed25519_verify_msg((byte*)sig, sigSz, msg, msgSz, &check, &key)) != MP_OKAY) { WOLFSSL_MSG("wc_ed25519_verify_msg failed"); } else if (!check) WOLFSSL_MSG("wc_ed25519_verify_msg failed (signature invalid)"); else ret = WOLFSSL_SUCCESS; wc_ed25519_free(&key); return ret; #endif /* HAVE_ED25519_VERIFY && WOLFSSL_KEY_GEN && HAVE_ED25519_KEY_IMPORT */ } #endif /* OPENSSL_EXTRA && HAVE_ED25519 */ #if defined(OPENSSL_EXTRA) && defined(HAVE_CURVE448) /* return 1 if success, 0 if error * output keys are little endian format */ int wolfSSL_EC448_generate_key(unsigned char *priv, unsigned int *privSz, unsigned char *pub, unsigned int *pubSz) { #ifndef WOLFSSL_KEY_GEN WOLFSSL_MSG("No Key Gen built in"); (void) priv; (void) privSz; (void) pub; (void) pubSz; return WOLFSSL_FAILURE; #else /* WOLFSSL_KEY_GEN */ int ret = WOLFSSL_FAILURE; int initTmpRng = 0; WC_RNG *rng = NULL; #ifdef WOLFSSL_SMALL_STACK WC_RNG *tmpRNG = NULL; #else WC_RNG tmpRNG[1]; #endif WOLFSSL_ENTER("wolfSSL_EC448_generate_key"); if (priv == NULL || privSz == NULL || *privSz < CURVE448_KEY_SIZE || pub == NULL || pubSz == NULL || *pubSz < CURVE448_KEY_SIZE) { WOLFSSL_MSG("Bad arguments"); return WOLFSSL_FAILURE; } #ifdef WOLFSSL_SMALL_STACK tmpRNG = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG); if (tmpRNG == NULL) return WOLFSSL_FAILURE; #endif if (wc_InitRng(tmpRNG) == 0) { rng = tmpRNG; initTmpRng = 1; } else { WOLFSSL_MSG("Bad RNG Init, trying global"); if (initGlobalRNG == 0) WOLFSSL_MSG("Global RNG no Init"); else rng = &globalRNG; } if (rng) { curve448_key key; if (wc_curve448_init(&key) != MP_OKAY) WOLFSSL_MSG("wc_curve448_init failed"); else if (wc_curve448_make_key(rng, CURVE448_KEY_SIZE, &key)!=MP_OKAY) WOLFSSL_MSG("wc_curve448_make_key failed"); /* export key pair */ else if (wc_curve448_export_key_raw_ex(&key, priv, privSz, pub, pubSz, EC448_LITTLE_ENDIAN) != MP_OKAY) WOLFSSL_MSG("wc_curve448_export_key_raw_ex failed"); else ret = WOLFSSL_SUCCESS; wc_curve448_free(&key); } if (initTmpRng) wc_FreeRng(tmpRNG); #ifdef WOLFSSL_SMALL_STACK XFREE(tmpRNG, NULL, DYNAMIC_TYPE_RNG); #endif return ret; #endif /* WOLFSSL_KEY_GEN */ } /* return 1 if success, 0 if error * input and output keys are little endian format */ int wolfSSL_EC448_shared_key(unsigned char *shared, unsigned int *sharedSz, const unsigned char *priv, unsigned int privSz, const unsigned char *pub, unsigned int pubSz) { #ifndef WOLFSSL_KEY_GEN WOLFSSL_MSG("No Key Gen built in"); (void) shared; (void) sharedSz; (void) priv; (void) privSz; (void) pub; (void) pubSz; return WOLFSSL_FAILURE; #else /* WOLFSSL_KEY_GEN */ int ret = WOLFSSL_FAILURE; curve448_key privkey, pubkey; WOLFSSL_ENTER("wolfSSL_EC448_shared_key"); if (shared == NULL || sharedSz == NULL || *sharedSz < CURVE448_KEY_SIZE || priv == NULL || privSz < CURVE448_KEY_SIZE || pub == NULL || pubSz < CURVE448_KEY_SIZE) { WOLFSSL_MSG("Bad arguments"); return WOLFSSL_FAILURE; } /* import private key */ if (wc_curve448_init(&privkey) != MP_OKAY) { WOLFSSL_MSG("wc_curve448_init privkey failed"); return ret; } if (wc_curve448_import_private_ex(priv, privSz, &privkey, EC448_LITTLE_ENDIAN) != MP_OKAY) { WOLFSSL_MSG("wc_curve448_import_private_ex failed"); wc_curve448_free(&privkey); return ret; } /* import public key */ if (wc_curve448_init(&pubkey) != MP_OKAY) { WOLFSSL_MSG("wc_curve448_init pubkey failed"); wc_curve448_free(&privkey); return ret; } if (wc_curve448_import_public_ex(pub, pubSz, &pubkey, EC448_LITTLE_ENDIAN) != MP_OKAY) { WOLFSSL_MSG("wc_curve448_import_public_ex failed"); wc_curve448_free(&privkey); wc_curve448_free(&pubkey); return ret; } if (wc_curve448_shared_secret_ex(&privkey, &pubkey, shared, sharedSz, EC448_LITTLE_ENDIAN) != MP_OKAY) WOLFSSL_MSG("wc_curve448_shared_secret_ex failed"); else ret = WOLFSSL_SUCCESS; wc_curve448_free(&privkey); wc_curve448_free(&pubkey); return ret; #endif /* WOLFSSL_KEY_GEN */ } #endif /* OPENSSL_EXTRA && HAVE_CURVE448 */ #if defined(OPENSSL_EXTRA) && defined(HAVE_ED448) /* return 1 if success, 0 if error * output keys are little endian format */ int wolfSSL_ED448_generate_key(unsigned char *priv, unsigned int *privSz, unsigned char *pub, unsigned int *pubSz) { #ifndef WOLFSSL_KEY_GEN WOLFSSL_MSG("No Key Gen built in"); (void) priv; (void) privSz; (void) pub; (void) pubSz; return WOLFSSL_FAILURE; #elif !defined(HAVE_ED448_KEY_EXPORT) WOLFSSL_MSG("No ED448 key export built in"); (void) priv; (void) privSz; (void) pub; (void) pubSz; return WOLFSSL_FAILURE; #else /* WOLFSSL_KEY_GEN && HAVE_ED448_KEY_EXPORT */ int ret = WOLFSSL_FAILURE; int initTmpRng = 0; WC_RNG *rng = NULL; #ifdef WOLFSSL_SMALL_STACK WC_RNG *tmpRNG = NULL; #else WC_RNG tmpRNG[1]; #endif WOLFSSL_ENTER("wolfSSL_ED448_generate_key"); if (priv == NULL || privSz == NULL || *privSz < ED448_PRV_KEY_SIZE || pub == NULL || pubSz == NULL || *pubSz < ED448_PUB_KEY_SIZE) { WOLFSSL_MSG("Bad arguments"); return WOLFSSL_FAILURE; } #ifdef WOLFSSL_SMALL_STACK tmpRNG = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG); if (tmpRNG == NULL) return WOLFSSL_FATAL_ERROR; #endif if (wc_InitRng(tmpRNG) == 0) { rng = tmpRNG; initTmpRng = 1; } else { WOLFSSL_MSG("Bad RNG Init, trying global"); if (initGlobalRNG == 0) WOLFSSL_MSG("Global RNG no Init"); else rng = &globalRNG; } if (rng) { ed448_key key; if (wc_ed448_init(&key) != MP_OKAY) WOLFSSL_MSG("wc_ed448_init failed"); else if (wc_ed448_make_key(rng, ED448_KEY_SIZE, &key) != MP_OKAY) WOLFSSL_MSG("wc_ed448_make_key failed"); /* export private key */ else if (wc_ed448_export_key(&key, priv, privSz, pub, pubSz) != MP_OKAY) WOLFSSL_MSG("wc_ed448_export_key failed"); else ret = WOLFSSL_SUCCESS; wc_ed448_free(&key); } if (initTmpRng) wc_FreeRng(tmpRNG); #ifdef WOLFSSL_SMALL_STACK XFREE(tmpRNG, NULL, DYNAMIC_TYPE_RNG); #endif return ret; #endif /* WOLFSSL_KEY_GEN && HAVE_ED448_KEY_EXPORT */ } /* return 1 if success, 0 if error * input and output keys are little endian format * priv is a buffer containing private and public part of key */ int wolfSSL_ED448_sign(const unsigned char *msg, unsigned int msgSz, const unsigned char *priv, unsigned int privSz, unsigned char *sig, unsigned int *sigSz) { #if !defined(HAVE_ED448_SIGN) || !defined(WOLFSSL_KEY_GEN) || !defined(HAVE_ED448_KEY_IMPORT) #if !defined(HAVE_ED448_SIGN) WOLFSSL_MSG("No ED448 sign built in"); #elif !defined(WOLFSSL_KEY_GEN) WOLFSSL_MSG("No Key Gen built in"); #elif !defined(HAVE_ED448_KEY_IMPORT) WOLFSSL_MSG("No ED448 Key import built in"); #endif (void) msg; (void) msgSz; (void) priv; (void) privSz; (void) sig; (void) sigSz; return WOLFSSL_FAILURE; #else /* HAVE_ED448_SIGN && WOLFSSL_KEY_GEN && HAVE_ED448_KEY_IMPORT */ ed448_key key; int ret = WOLFSSL_FAILURE; WOLFSSL_ENTER("wolfSSL_ED448_sign"); if (priv == NULL || privSz != ED448_PRV_KEY_SIZE || msg == NULL || sig == NULL || *sigSz < ED448_SIG_SIZE) { WOLFSSL_MSG("Bad arguments"); return WOLFSSL_FAILURE; } /* import key */ if (wc_ed448_init(&key) != MP_OKAY) { WOLFSSL_MSG("wc_curve448_init failed"); return ret; } if (wc_ed448_import_private_key(priv, privSz/2, priv+(privSz/2), ED448_PUB_KEY_SIZE, &key) != MP_OKAY){ WOLFSSL_MSG("wc_ed448_import_private failed"); wc_ed448_free(&key); return ret; } if (wc_ed448_sign_msg(msg, msgSz, sig, sigSz, &key, NULL, 0) != MP_OKAY) WOLFSSL_MSG("wc_curve448_shared_secret_ex failed"); else ret = WOLFSSL_SUCCESS; wc_ed448_free(&key); return ret; #endif /* HAVE_ED448_SIGN && WOLFSSL_KEY_GEN && HAVE_ED448_KEY_IMPORT */ } /* return 1 if success, 0 if error * input and output keys are little endian format * pub is a buffer containing public part of key */ int wolfSSL_ED448_verify(const unsigned char *msg, unsigned int msgSz, const unsigned char *pub, unsigned int pubSz, const unsigned char *sig, unsigned int sigSz) { #if !defined(HAVE_ED448_VERIFY) || !defined(WOLFSSL_KEY_GEN) || !defined(HAVE_ED448_KEY_IMPORT) #if !defined(HAVE_ED448_VERIFY) WOLFSSL_MSG("No ED448 verify built in"); #elif !defined(WOLFSSL_KEY_GEN) WOLFSSL_MSG("No Key Gen built in"); #elif !defined(HAVE_ED448_KEY_IMPORT) WOLFSSL_MSG("No ED448 Key import built in"); #endif (void) msg; (void) msgSz; (void) pub; (void) pubSz; (void) sig; (void) sigSz; return WOLFSSL_FAILURE; #else /* HAVE_ED448_VERIFY && WOLFSSL_KEY_GEN && HAVE_ED448_KEY_IMPORT */ ed448_key key; int ret = WOLFSSL_FAILURE, check = 0; WOLFSSL_ENTER("wolfSSL_ED448_verify"); if (pub == NULL || pubSz != ED448_PUB_KEY_SIZE || msg == NULL || sig == NULL || sigSz != ED448_SIG_SIZE) { WOLFSSL_MSG("Bad arguments"); return WOLFSSL_FAILURE; } /* import key */ if (wc_ed448_init(&key) != MP_OKAY) { WOLFSSL_MSG("wc_curve448_init failed"); return ret; } if (wc_ed448_import_public(pub, pubSz, &key) != MP_OKAY){ WOLFSSL_MSG("wc_ed448_import_public failed"); wc_ed448_free(&key); return ret; } if ((ret = wc_ed448_verify_msg((byte*)sig, sigSz, msg, msgSz, &check, &key, NULL, 0)) != MP_OKAY) { WOLFSSL_MSG("wc_ed448_verify_msg failed"); } else if (!check) WOLFSSL_MSG("wc_ed448_verify_msg failed (signature invalid)"); else ret = WOLFSSL_SUCCESS; wc_ed448_free(&key); return ret; #endif /* HAVE_ED448_VERIFY && WOLFSSL_KEY_GEN */ } #endif /* OPENSSL_EXTRA && HAVE_ED448 */ #ifdef WOLFSSL_JNI int wolfSSL_set_jobject(WOLFSSL* ssl, void* objPtr) { WOLFSSL_ENTER("wolfSSL_set_jobject"); if (ssl != NULL) { ssl->jObjectRef = objPtr; return WOLFSSL_SUCCESS; } return WOLFSSL_FAILURE; } void* wolfSSL_get_jobject(WOLFSSL* ssl) { WOLFSSL_ENTER("wolfSSL_get_jobject"); if (ssl != NULL) return ssl->jObjectRef; return NULL; } #endif /* WOLFSSL_JNI */ #ifdef WOLFSSL_ASYNC_CRYPT int wolfSSL_CTX_AsyncPoll(WOLFSSL_CTX* ctx, WOLF_EVENT** events, int maxEvents, WOLF_EVENT_FLAG flags, int* eventCount) { if (ctx == NULL) { return BAD_FUNC_ARG; } return wolfAsync_EventQueuePoll(&ctx->event_queue, NULL, events, maxEvents, flags, eventCount); } int wolfSSL_AsyncPoll(WOLFSSL* ssl, WOLF_EVENT_FLAG flags) { int ret, eventCount = 0; WOLF_EVENT* events[1]; if (ssl == NULL) { return BAD_FUNC_ARG; } ret = wolfAsync_EventQueuePoll(&ssl->ctx->event_queue, ssl, events, sizeof(events)/sizeof(events[0]), flags, &eventCount); if (ret == 0) { ret = eventCount; } return ret; } #endif /* WOLFSSL_ASYNC_CRYPT */ #ifdef OPENSSL_EXTRA unsigned long wolfSSL_ERR_peek_error_line_data(const char **file, int *line, const char **data, int *flags) { WOLFSSL_ENTER("wolfSSL_ERR_peek_error_line_data"); (void)line; (void)file; /* No data or flags stored - error display only in Nginx. */ if (data != NULL) { *data = ""; } if (flags != NULL) { *flags = 0; } #ifdef WOLFSSL_HAVE_ERROR_QUEUE { int ret = 0; while (1) { ret = wc_PeekErrorNode(-1, file, NULL, line); if (ret == BAD_MUTEX_E || ret == BAD_FUNC_ARG || ret == BAD_STATE_E) { WOLFSSL_MSG("Issue peeking at error node in queue"); return 0; } /* OpenSSL uses positive error codes */ if (ret < 0) { ret = -ret; } 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; } #endif if (ret != -WANT_READ && ret != -WANT_WRITE && ret != -ZERO_RETURN && ret != -WOLFSSL_ERROR_ZERO_RETURN && ret != -SOCKET_PEER_CLOSED_E && ret != -SOCKET_ERROR_E) break; wc_RemoveErrorNode(-1); } return (unsigned long)ret; } #else return (unsigned long)(0 - NOT_COMPILED_IN); #endif } #endif #if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) #if !defined(WOLFSSL_USER_IO) /* converts an IPv6 or IPv4 address into an octet string for use with rfc3280 * example input would be "127.0.0.1" and the returned value would be 7F000001 */ WOLFSSL_ASN1_STRING* wolfSSL_a2i_IPADDRESS(const char* ipa) { int ipaSz = WOLFSSL_IP4_ADDR_LEN; char buf[WOLFSSL_IP6_ADDR_LEN + 1]; /* plus 1 for terminator */ int af = WOLFSSL_IP4; WOLFSSL_ASN1_STRING *ret = NULL; if (ipa == NULL) return NULL; if (XSTRSTR(ipa, ":") != NULL) { af = WOLFSSL_IP6; ipaSz = WOLFSSL_IP6_ADDR_LEN; } buf[WOLFSSL_IP6_ADDR_LEN] = '\0'; if (XINET_PTON(af, ipa, (void*)buf) != 1) { WOLFSSL_MSG("Error parsing IP address"); return NULL; } ret = wolfSSL_ASN1_STRING_new(); if (ret != NULL) { if (wolfSSL_ASN1_STRING_set(ret, buf, ipaSz) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("Error setting the string"); wolfSSL_ASN1_STRING_free(ret); ret = NULL; } } return ret; } #endif /* !WOLFSSL_USER_IO */ /* Is the specified cipher suite a fake one used an an extension proxy? */ static WC_INLINE int SCSV_Check(byte suite0, byte suite) { (void)suite0; (void)suite; #ifdef HAVE_RENEGOTIATION_INDICATION if (suite0 == CIPHER_BYTE && suite == TLS_EMPTY_RENEGOTIATION_INFO_SCSV) return 1; #endif return 0; } static WC_INLINE int sslCipherMinMaxCheck(const WOLFSSL *ssl, byte suite0, byte suite) { const CipherSuiteInfo* cipher_names = GetCipherNames(); int cipherSz = GetCipherNamesSize(); int i; for (i = 0; i < cipherSz; i++) if (cipher_names[i].cipherSuite0 == suite0 && cipher_names[i].cipherSuite == suite) break; if (i == cipherSz) return 1; /* Check min version */ if (cipher_names[i].minor < ssl->options.minDowngrade) { if (ssl->options.minDowngrade <= TLSv1_2_MINOR && cipher_names[i].minor >= TLSv1_MINOR) /* 1.0 ciphersuites are in general available in 1.1 and * 1.1 ciphersuites are in general available in 1.2 */ return 0; return 1; } /* Check max version */ switch (cipher_names[i].minor) { case SSLv3_MINOR : return ssl->options.mask & WOLFSSL_OP_NO_SSLv3; case TLSv1_MINOR : return ssl->options.mask & WOLFSSL_OP_NO_TLSv1; case TLSv1_1_MINOR : return ssl->options.mask & WOLFSSL_OP_NO_TLSv1_1; case TLSv1_2_MINOR : return ssl->options.mask & WOLFSSL_OP_NO_TLSv1_2; case TLSv1_3_MINOR : return ssl->options.mask & WOLFSSL_OP_NO_TLSv1_3; default: WOLFSSL_MSG("Unrecognized minor version"); return 1; } } /* returns a pointer to internal cipher suite list. Should not be free'd by * caller. */ WOLF_STACK_OF(WOLFSSL_CIPHER) *wolfSSL_get_ciphers_compat(const WOLFSSL *ssl) { WOLF_STACK_OF(WOLFSSL_CIPHER)* ret = NULL; Suites* suites; #if defined(OPENSSL_ALL) || defined(WOLFSSL_QT) const CipherSuiteInfo* cipher_names = GetCipherNames(); int cipherSz = GetCipherNamesSize(); #endif WOLFSSL_ENTER("wolfSSL_get_ciphers_compat"); if (ssl == NULL || (ssl->suites == NULL && ssl->ctx->suites == NULL)) { return NULL; } if (ssl->suites != NULL) { if (ssl->suites->suiteSz == 0 && InitSSL_Suites((WOLFSSL*)ssl) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("Suite initialization failure"); return NULL; } suites = ssl->suites; } else { suites = ssl->ctx->suites; } /* check if stack needs populated */ if (suites->stack == NULL) { int i; #if defined(OPENSSL_ALL) || defined(WOLFSSL_QT) int j; /* higher priority of cipher suite will be on top of stack */ for (i = suites->suiteSz - 2; i >=0; i-=2) { #else for (i = 0; i < suites->suiteSz; i+=2) { #endif WOLFSSL_STACK* add; /* A couple of suites are placeholders for special options, * skip those. */ if (SCSV_Check(suites->suites[i], suites->suites[i+1]) || sslCipherMinMaxCheck(ssl, suites->suites[i], suites->suites[i+1])) { continue; } add = wolfSSL_sk_new_node(ssl->heap); if (add != NULL) { add->type = STACK_TYPE_CIPHER; add->data.cipher.cipherSuite0 = suites->suites[i]; add->data.cipher.cipherSuite = suites->suites[i+1]; add->data.cipher.ssl = ssl; #if defined(OPENSSL_ALL) || defined(WOLFSSL_QT) for (j = 0; j < cipherSz; j++) { if (cipher_names[j].cipherSuite0 == add->data.cipher.cipherSuite0 && cipher_names[j].cipherSuite == add->data.cipher.cipherSuite) { add->data.cipher.offset = j; break; } } #endif #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) /* in_stack is checked in wolfSSL_CIPHER_description */ add->data.cipher.in_stack = 1; #endif add->next = ret; if (ret != NULL) { add->num = ret->num + 1; } else { add->num = 1; } ret = add; } } suites->stack = ret; } return suites->stack; } #endif /* OPENSSL_ALL || WOLFSSL_NGINX || WOLFSSL_HAPROXY */ #if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) \ || defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY) || defined(HAVE_SECRET_CALLBACK) long wolfSSL_SSL_CTX_get_timeout(const WOLFSSL_CTX *ctx) { WOLFSSL_ENTER("wolfSSL_SSL_CTX_get_timeout"); if (ctx == NULL) return 0; return ctx->timeout; } /* returns the time in seconds of the current timeout */ long wolfSSL_get_timeout(WOLFSSL* ssl) { WOLFSSL_ENTER("wolfSSL_get_timeout"); if (ssl == NULL) return 0; return ssl->timeout; } #endif #if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) \ || defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY) #ifdef HAVE_ECC int wolfSSL_SSL_CTX_set_tmp_ecdh(WOLFSSL_CTX *ctx, WOLFSSL_EC_KEY *ecdh) { WOLFSSL_ENTER("wolfSSL_SSL_CTX_set_tmp_ecdh"); if (ctx == NULL || ecdh == NULL) return BAD_FUNC_ARG; ctx->ecdhCurveOID = ecdh->group->curve_oid; return WOLFSSL_SUCCESS; } #endif /* Assumes that the session passed in is from the cache. */ int wolfSSL_SSL_CTX_remove_session(WOLFSSL_CTX *ctx, WOLFSSL_SESSION *s) { WOLFSSL_ENTER("wolfSSL_SSL_CTX_remove_session"); s = ClientSessionToSession(s); if (ctx == NULL || s == NULL) return BAD_FUNC_ARG; #ifdef HAVE_EXT_CACHE if (!ctx->internalCacheOff) #endif { /* Don't remove session just timeout session. */ s->timeout = 0; #ifndef NO_SESSION_CACHE /* Clear the timeout in the cache */ { int row; int i; SessionRow* sessRow = NULL; WOLFSSL_SESSION *cacheSession; const byte* id; int ret = 0; id = s->sessionID; if (s->haveAltSessionID) id = s->altSessionID; row = (int)(HashSession(id, ID_LEN, &ret) % SESSION_ROWS); if (ret != 0) { WOLFSSL_MSG("Hash session failed"); return ret; } sessRow = &SessionCache[row]; if (SESSION_ROW_LOCK(sessRow) != 0) { WOLFSSL_MSG("Session row lock failed"); return BAD_MUTEX_E; } for (i = 0; i < SESSIONS_PER_ROW && i < sessRow->totalCount; i++) { cacheSession = &sessRow->Sessions[i]; if (XMEMCMP(id, cacheSession->sessionID, ID_LEN) == 0) { if (ctx->method->side != cacheSession->side) continue; cacheSession->timeout = 0; #ifdef HAVE_EX_DATA if (cacheSession->ownExData) { /* Most recent version of ex data is in cache. Copy it * over so the user can free it. */ XMEMCPY(&s->ex_data, &cacheSession->ex_data, sizeof(WOLFSSL_CRYPTO_EX_DATA)); } cacheSession->ownExData = 0; /* We clear below */ s->ownExData = 1; #endif break; } } SESSION_ROW_UNLOCK(sessRow); } #endif } #if defined(HAVE_EXT_CACHE) || defined(HAVE_EX_DATA) if (ctx->rem_sess_cb != NULL) { ctx->rem_sess_cb(ctx, s); } #endif return 0; } #ifndef NO_BIO BIO *wolfSSL_SSL_get_rbio(const WOLFSSL *s) { WOLFSSL_ENTER("wolfSSL_SSL_get_rbio"); /* Nginx sets the buffer size if the read BIO is different to write BIO. * The setting buffer size doesn't do anything so return NULL for both. */ if (s == NULL) return NULL; return s->biord; } BIO *wolfSSL_SSL_get_wbio(const WOLFSSL *s) { WOLFSSL_ENTER("wolfSSL_SSL_get_wbio"); (void)s; /* Nginx sets the buffer size if the read BIO is different to write BIO. * The setting buffer size doesn't do anything so return NULL for both. */ if (s == NULL) return NULL; return s->biowr; } #endif /* !NO_BIO */ int wolfSSL_SSL_do_handshake(WOLFSSL *s) { WOLFSSL_ENTER("wolfSSL_SSL_do_handshake"); if (s == NULL) return WOLFSSL_FAILURE; if (s->options.side == WOLFSSL_CLIENT_END) { #ifndef NO_WOLFSSL_CLIENT return wolfSSL_connect(s); #else WOLFSSL_MSG("Client not compiled in"); return WOLFSSL_FAILURE; #endif } #ifndef NO_WOLFSSL_SERVER return wolfSSL_accept(s); #else WOLFSSL_MSG("Server not compiled in"); return WOLFSSL_FAILURE; #endif } #if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000L int wolfSSL_SSL_in_init(const WOLFSSL *ssl) #else int wolfSSL_SSL_in_init(WOLFSSL *ssl) #endif { WOLFSSL_ENTER("SSL_in_init"); if (ssl == NULL) return WOLFSSL_FAILURE; if (ssl->options.side == WOLFSSL_CLIENT_END) { return ssl->options.connectState < SECOND_REPLY_DONE; } return ssl->options.acceptState < ACCEPT_THIRD_REPLY_DONE; } int wolfSSL_SSL_in_connect_init(WOLFSSL* ssl) { WOLFSSL_ENTER("SSL_connect_init"); if (ssl == NULL) return WOLFSSL_FAILURE; if (ssl->options.side == WOLFSSL_CLIENT_END) { return ssl->options.connectState > CONNECT_BEGIN && ssl->options.connectState < SECOND_REPLY_DONE; } return ssl->options.acceptState > ACCEPT_BEGIN && ssl->options.acceptState < ACCEPT_THIRD_REPLY_DONE; } #ifndef NO_SESSION_CACHE WOLFSSL_SESSION *wolfSSL_SSL_get0_session(const WOLFSSL *ssl) { WOLFSSL_ENTER("wolfSSL_SSL_get0_session"); return ssl->session; } #endif /* NO_SESSION_CACHE */ #ifndef NO_BIO int wolfSSL_a2i_ASN1_INTEGER(WOLFSSL_BIO *bio, WOLFSSL_ASN1_INTEGER *asn1, char *buf, int size) { int readNextLine; int lineLen; int len; byte isNumCheck; word32 outLen; const int extraTagSz = MAX_LENGTH_SZ + 1; byte intTag[MAX_LENGTH_SZ + 1]; int idx = 0; WOLFSSL_ENTER("wolfSSL_a2i_ASN1_INTEGER"); if (!bio || !asn1 || !buf || size <= 0) { WOLFSSL_MSG("Bad parameter"); return WOLFSSL_FAILURE; } /* Reset asn1 */ if (asn1->isDynamic && asn1->data) { XFREE(asn1->data, NULL, DYNAMIC_TYPE_OPENSSL); } XMEMSET(asn1->intData, 0, WOLFSSL_ASN1_INTEGER_MAX); asn1->data = asn1->intData; asn1->isDynamic = 0; asn1->length = 0; asn1->negative = 0; asn1->type = V_ASN1_INTEGER; lineLen = wolfSSL_BIO_gets(bio, buf, size); do { readNextLine = 0; if (lineLen <= 0) { WOLFSSL_MSG("wolfSSL_BIO_gets error"); return WOLFSSL_FAILURE; } while (lineLen && (buf[lineLen-1] == '\n' || buf[lineLen-1] == '\r')) lineLen--; if (buf[lineLen-1] == '\\') readNextLine = 1; /* Ignore none-hex chars at the end of the line */ outLen = 1; while (lineLen && Base16_Decode((byte*)buf + lineLen - 1, 1, &isNumCheck, &outLen) == ASN_INPUT_E) lineLen--; if (!lineLen || lineLen % 2) { WOLFSSL_MSG("Invalid line length"); return WOLFSSL_FAILURE; } len = asn1->length + (lineLen/2); /* Check if it will fit in static memory and * save space for the ASN tag in front */ if (len > (int)(WOLFSSL_ASN1_INTEGER_MAX - extraTagSz)) { /* Allocate mem for data */ if (asn1->isDynamic) { byte* tmp = (byte*)XREALLOC(asn1->data, len + extraTagSz, NULL, DYNAMIC_TYPE_OPENSSL); if (!tmp) { WOLFSSL_MSG("realloc error"); return WOLFSSL_FAILURE; } asn1->data = tmp; } else { /* Up to this point asn1->data pointed to asn1->intData. * Now that the size has grown larger than intData can handle * the asn1 structure moves to a dynamic type with isDynamic * flag being set and asn1->data being malloc'd. */ asn1->data = (byte*)XMALLOC(len + extraTagSz, NULL, DYNAMIC_TYPE_OPENSSL); if (!asn1->data) { WOLFSSL_MSG("malloc error"); return WOLFSSL_FAILURE; } asn1->isDynamic = 1; XMEMCPY(asn1->data, asn1->intData, asn1->length); } } len = lineLen/2; if (Base16_Decode((byte*)buf, lineLen, asn1->data + asn1->length, (word32*)&len) != 0) { WOLFSSL_MSG("Base16_Decode error"); return WOLFSSL_FAILURE; } asn1->length += len; } while (readNextLine); /* Write ASN tag */ idx = SetASNInt(asn1->length, asn1->data[0], intTag); XMEMMOVE(asn1->data + idx, asn1->data, asn1->length); XMEMCPY(asn1->data, intTag, idx); asn1->dataMax = asn1->length += idx; return WOLFSSL_SUCCESS; } int wolfSSL_i2a_ASN1_INTEGER(BIO *bp, const WOLFSSL_ASN1_INTEGER *a) { word32 idx = 1; int len = 0; byte buf[512]; word32 bufLen = 512; WOLFSSL_ENTER("wolfSSL_i2a_ASN1_INTEGER"); if (bp == NULL || a == NULL) return WOLFSSL_FAILURE; /* Skip ASN.1 INTEGER (type) byte. */ if (a->data[idx] == 0x80 || /* Indefinite length, can't determine length */ GetLength(a->data, &idx, &len, a->length) < 0) { return 0; } /* Zero length integer is the value zero. */ if (len == 0) { return wolfSSL_BIO_write(bp, "00", 2); } if (Base16_Encode(a->data + idx, len, buf, &bufLen) != 0 || bufLen == 0) { return 0; } return wolfSSL_BIO_write(bp, buf, bufLen - 1); /* Don't write out NULL char */ } #endif /* !NO_BIO */ #if defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_SERVER) /* Expected return values from implementations of OpenSSL ticket key callback. */ #define TICKET_KEY_CB_RET_FAILURE (-1) #define TICKET_KEY_CB_RET_NOT_FOUND 0 #define TICKET_KEY_CB_RET_OK 1 #define TICKET_KEY_CB_RET_RENEW 2 /* Implementation of session ticket encryption/decryption using OpenSSL * callback to initialize the cipher and HMAC. * * ssl The SSL/TLS object. * keyName The key name - used to identify the key to be used. * iv The IV to use. * mac The MAC of the encrypted data. * enc Encrypt ticket. * encTicket The ticket data. * encTicketLen The length of the ticket data. * encLen The encrypted/decrypted ticket length - output length. * ctx Ignored. Application specific data. * returns WOLFSSL_TICKET_RET_OK to indicate success, * WOLFSSL_TICKET_RET_CREATE if a new ticket is required and * WOLFSSL_TICKET_RET_FATAL on error. */ static int wolfSSL_TicketKeyCb(WOLFSSL* ssl, unsigned char keyName[WOLFSSL_TICKET_NAME_SZ], unsigned char iv[WOLFSSL_TICKET_IV_SZ], unsigned char mac[WOLFSSL_TICKET_MAC_SZ], int enc, unsigned char* encTicket, int encTicketLen, int* encLen, void* ctx) { byte digest[WC_MAX_DIGEST_SIZE]; WOLFSSL_EVP_CIPHER_CTX evpCtx; WOLFSSL_HMAC_CTX hmacCtx; unsigned int mdSz = 0; int len = 0; int ret = WOLFSSL_TICKET_RET_FATAL; int res; (void)ctx; WOLFSSL_ENTER("wolfSSL_TicketKeyCb"); if (ssl == NULL || ssl->ctx == NULL || ssl->ctx->ticketEncWrapCb == NULL) { WOLFSSL_MSG("Bad parameter"); return WOLFSSL_TICKET_RET_FATAL; } /* Initialize the cipher and HMAC. */ wolfSSL_EVP_CIPHER_CTX_init(&evpCtx); if (wolfSSL_HMAC_CTX_Init(&hmacCtx) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("wolfSSL_HMAC_CTX_Init error"); return WOLFSSL_TICKET_RET_FATAL; } res = ssl->ctx->ticketEncWrapCb(ssl, keyName, iv, &evpCtx, &hmacCtx, enc); if (res != TICKET_KEY_CB_RET_OK && res != TICKET_KEY_CB_RET_RENEW) { WOLFSSL_MSG("Ticket callback error"); ret = WOLFSSL_TICKET_RET_FATAL; goto end; } if (enc) { /* Encrypt in place. */ if (!wolfSSL_EVP_CipherUpdate(&evpCtx, encTicket, &len, encTicket, encTicketLen)) goto end; encTicketLen = len; if (!wolfSSL_EVP_EncryptFinal(&evpCtx, &encTicket[encTicketLen], &len)) goto end; /* Total length of encrypted data. */ encTicketLen += len; *encLen = encTicketLen; /* HMAC the encrypted data into the parameter 'mac'. */ if (!wolfSSL_HMAC_Update(&hmacCtx, encTicket, encTicketLen)) goto end; #ifdef WOLFSSL_SHA512 /* Check for SHA512, which would overrun the mac buffer */ if (hmacCtx.hmac.macType == WC_SHA512) goto end; #endif if (!wolfSSL_HMAC_Final(&hmacCtx, mac, &mdSz)) goto end; } else { /* HMAC the encrypted data and compare it to the passed in data. */ if (!wolfSSL_HMAC_Update(&hmacCtx, encTicket, encTicketLen)) goto end; if (!wolfSSL_HMAC_Final(&hmacCtx, digest, &mdSz)) goto end; if (XMEMCMP(mac, digest, mdSz) != 0) goto end; /* Decrypt the ticket data in place. */ if (!wolfSSL_EVP_CipherUpdate(&evpCtx, encTicket, &len, encTicket, encTicketLen)) goto end; encTicketLen = len; if (!wolfSSL_EVP_DecryptFinal(&evpCtx, &encTicket[encTicketLen], &len)) goto end; /* Total length of decrypted data. */ *encLen = encTicketLen + len; } if (res == TICKET_KEY_CB_RET_RENEW && !IsAtLeastTLSv1_3(ssl->version) && !enc) ret = WOLFSSL_TICKET_RET_CREATE; else ret = WOLFSSL_TICKET_RET_OK; end: (void)wc_HmacFree(&hmacCtx.hmac); return ret; } /* Set the callback to use when encrypting/decrypting tickets. * * ctx The SSL/TLS context object. * cb The OpenSSL session ticket callback. * returns WOLFSSL_SUCCESS to indicate success. */ int wolfSSL_CTX_set_tlsext_ticket_key_cb(WOLFSSL_CTX *ctx, ticketCompatCb cb) { /* Set the ticket encryption callback to be a wrapper around OpenSSL * callback. */ ctx->ticketEncCb = wolfSSL_TicketKeyCb; ctx->ticketEncWrapCb = cb; return WOLFSSL_SUCCESS; } #endif /* HAVE_SESSION_TICKET */ #endif /* OPENSSL_ALL || WOLFSSL_NGINX || WOLFSSL_HAPROXY || OPENSSL_EXTRA || HAVE_LIGHTY */ #if defined(HAVE_SESSION_TICKET) && !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \ !defined(NO_WOLFSSL_SERVER) /* Serialize the session ticket encryption keys. * * @param [in] ctx SSL/TLS context object. * @param [in] keys Buffer to hold session ticket keys. * @param [in] keylen Length of buffer. * @return WOLFSSL_SUCCESS on success. * @return WOLFSSL_FAILURE when ctx is NULL, keys is NULL or keylen is not the * correct length. */ long wolfSSL_CTX_get_tlsext_ticket_keys(WOLFSSL_CTX *ctx, unsigned char *keys, int keylen) { if (ctx == NULL || keys == NULL) { return WOLFSSL_FAILURE; } if (keylen != WOLFSSL_TICKET_KEYS_SZ) { return WOLFSSL_FAILURE; } XMEMCPY(keys, ctx->ticketKeyCtx.name, WOLFSSL_TICKET_NAME_SZ); keys += WOLFSSL_TICKET_NAME_SZ; XMEMCPY(keys, ctx->ticketKeyCtx.key[0], WOLFSSL_TICKET_KEY_SZ); keys += WOLFSSL_TICKET_KEY_SZ; XMEMCPY(keys, ctx->ticketKeyCtx.key[1], WOLFSSL_TICKET_KEY_SZ); keys += WOLFSSL_TICKET_KEY_SZ; c32toa(ctx->ticketKeyCtx.expirary[0], keys); keys += OPAQUE32_LEN; c32toa(ctx->ticketKeyCtx.expirary[1], keys); return WOLFSSL_SUCCESS; } /* Deserialize the session ticket encryption keys. * * @param [in] ctx SSL/TLS context object. * @param [in] keys Session ticket keys. * @param [in] keylen Length of data. * @return WOLFSSL_SUCCESS on success. * @return WOLFSSL_FAILURE when ctx is NULL, keys is NULL or keylen is not the * correct length. */ long wolfSSL_CTX_set_tlsext_ticket_keys(WOLFSSL_CTX *ctx, unsigned char *keys, int keylen) { if (ctx == NULL || keys == NULL) { return WOLFSSL_FAILURE; } if (keylen != WOLFSSL_TICKET_KEYS_SZ) { return WOLFSSL_FAILURE; } XMEMCPY(ctx->ticketKeyCtx.name, keys, WOLFSSL_TICKET_NAME_SZ); keys += WOLFSSL_TICKET_NAME_SZ; XMEMCPY(ctx->ticketKeyCtx.key[0], keys, WOLFSSL_TICKET_KEY_SZ); keys += WOLFSSL_TICKET_KEY_SZ; XMEMCPY(ctx->ticketKeyCtx.key[1], keys, WOLFSSL_TICKET_KEY_SZ); keys += WOLFSSL_TICKET_KEY_SZ; ato32(keys, &ctx->ticketKeyCtx.expirary[0]); keys += OPAQUE32_LEN; ato32(keys, &ctx->ticketKeyCtx.expirary[1]); return WOLFSSL_SUCCESS; } #endif #if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) #ifdef HAVE_OCSP /* Not an OpenSSL API. */ int wolfSSL_get_ocsp_response(WOLFSSL* ssl, byte** response) { *response = ssl->ocspResp; return ssl->ocspRespSz; } /* Not an OpenSSL API. */ char* wolfSSL_get_ocsp_url(WOLFSSL* ssl) { return ssl->url; } /* Not an OpenSSL API. */ int wolfSSL_set_ocsp_url(WOLFSSL* ssl, char* url) { if (ssl == NULL) return WOLFSSL_FAILURE; ssl->url = url; return WOLFSSL_SUCCESS; } #endif /* OCSP */ #endif /* OPENSSL_ALL || WOLFSSL_NGINX || WOLFSSL_HAPROXY */ #if defined(HAVE_OCSP) && !defined(NO_ASN_TIME) int wolfSSL_get_ocsp_producedDate( WOLFSSL *ssl, byte *producedDate, size_t producedDate_space, int *producedDateFormat) { if ((ssl->ocspProducedDateFormat != ASN_UTC_TIME) && (ssl->ocspProducedDateFormat != ASN_GENERALIZED_TIME)) return BAD_FUNC_ARG; if ((producedDate == NULL) || (producedDateFormat == NULL)) return BAD_FUNC_ARG; if (XSTRLEN((char *)ssl->ocspProducedDate) >= producedDate_space) return BUFFER_E; XSTRNCPY((char *)producedDate, (const char *)ssl->ocspProducedDate, producedDate_space); *producedDateFormat = ssl->ocspProducedDateFormat; return 0; } int wolfSSL_get_ocsp_producedDate_tm(WOLFSSL *ssl, struct tm *produced_tm) { int idx = 0; if ((ssl->ocspProducedDateFormat != ASN_UTC_TIME) && (ssl->ocspProducedDateFormat != ASN_GENERALIZED_TIME)) return BAD_FUNC_ARG; if (produced_tm == NULL) return BAD_FUNC_ARG; if (ExtractDate(ssl->ocspProducedDate, (unsigned char)ssl->ocspProducedDateFormat, produced_tm, &idx)) return 0; else return ASN_PARSE_E; } #endif #if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) || \ defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) int wolfSSL_CTX_get_extra_chain_certs(WOLFSSL_CTX* ctx, WOLF_STACK_OF(X509)** chain) { word32 idx; word32 length; WOLFSSL_STACK* node; WOLFSSL_STACK* last = NULL; if (ctx == NULL || chain == NULL) { chain = NULL; return WOLFSSL_FAILURE; } if (ctx->x509Chain != NULL) { *chain = ctx->x509Chain; return WOLFSSL_SUCCESS; } /* If there are no chains then success! */ *chain = NULL; if (ctx->certChain == NULL || ctx->certChain->length == 0) { return WOLFSSL_SUCCESS; } /* Create a new stack of WOLFSSL_X509 object from chain buffer. */ for (idx = 0; idx < ctx->certChain->length; ) { node = (WOLFSSL_STACK*)XMALLOC(sizeof(WOLFSSL_STACK), NULL, DYNAMIC_TYPE_OPENSSL); if (node == NULL) return WOLFSSL_FAILURE; node->next = NULL; /* 3 byte length | X509 DER data */ ato24(ctx->certChain->buffer + idx, &length); idx += 3; /* Create a new X509 from DER encoded data. */ node->data.x509 = wolfSSL_X509_d2i(NULL, ctx->certChain->buffer + idx, length); if (node->data.x509 == NULL) { XFREE(node, NULL, DYNAMIC_TYPE_OPENSSL); /* Return as much of the chain as we created. */ ctx->x509Chain = *chain; return WOLFSSL_FAILURE; } idx += length; /* Add object to the end of the stack. */ if (last == NULL) { node->num = 1; *chain = node; } else { (*chain)->num++; last->next = node; } last = node; } ctx->x509Chain = *chain; return WOLFSSL_SUCCESS; } int wolfSSL_CTX_get_tlsext_status_cb(WOLFSSL_CTX* ctx, tlsextStatusCb* cb) { if (ctx == NULL || ctx->cm == NULL || cb == NULL) return WOLFSSL_FAILURE; #if !defined(NO_WOLFSSL_SERVER) && (defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)) if (ctx->cm->ocsp_stapling == NULL) return WOLFSSL_FAILURE; *cb = ctx->cm->ocsp_stapling->statusCb; #else (void)cb; *cb = NULL; #endif return WOLFSSL_SUCCESS; } int wolfSSL_CTX_set_tlsext_status_cb(WOLFSSL_CTX* ctx, tlsextStatusCb cb) { if (ctx == NULL || ctx->cm == NULL) return WOLFSSL_FAILURE; #if !defined(NO_WOLFSSL_SERVER) && (defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)) /* Ensure stapling is on for callback to be used. */ wolfSSL_CTX_EnableOCSPStapling(ctx); if (ctx->cm->ocsp_stapling == NULL) return WOLFSSL_FAILURE; ctx->cm->ocsp_stapling->statusCb = cb; #else (void)cb; #endif return WOLFSSL_SUCCESS; } int wolfSSL_CTX_get0_chain_certs(WOLFSSL_CTX *ctx, WOLF_STACK_OF(WOLFSSL_X509) **sk) { WOLFSSL_ENTER("wolfSSL_CTX_get0_chain_certs"); if (ctx == NULL || sk == NULL) { WOLFSSL_MSG("Bad parameter"); return WOLFSSL_FAILURE; } *sk = ctx->x509Chain; return WOLFSSL_SUCCESS; } #ifdef KEEP_OUR_CERT int wolfSSL_get0_chain_certs(WOLFSSL *ssl, WOLF_STACK_OF(WOLFSSL_X509) **sk) { WOLFSSL_ENTER("wolfSSL_get0_chain_certs"); if (ssl == NULL || sk == NULL) { WOLFSSL_MSG("Bad parameter"); return WOLFSSL_FAILURE; } *sk = ssl->ourCertChain; return WOLFSSL_SUCCESS; } #endif WOLF_STACK_OF(WOLFSSL_STRING)* wolfSSL_sk_WOLFSSL_STRING_new(void) { WOLF_STACK_OF(WOLFSSL_STRING)* ret = wolfSSL_sk_new_node(NULL); if (ret) { ret->type = STACK_TYPE_STRING; } return ret; } void wolfSSL_WOLFSSL_STRING_free(WOLFSSL_STRING s) { WOLFSSL_ENTER("wolfSSL_WOLFSSL_STRING_free"); if (s != NULL) XFREE(s, NULL, DYNAMIC_TYPE_OPENSSL); } void wolfSSL_sk_WOLFSSL_STRING_free(WOLF_STACK_OF(WOLFSSL_STRING)* sk) { WOLFSSL_STACK* tmp; WOLFSSL_ENTER("wolfSSL_sk_WOLFSSL_STRING_free"); if (sk == NULL) return; /* parse through stack freeing each node */ while (sk) { tmp = sk->next; XFREE(sk->data.string, NULL, DYNAMIC_TYPE_OPENSSL); XFREE(sk, NULL, DYNAMIC_TYPE_OPENSSL); sk = tmp; } } WOLFSSL_STRING wolfSSL_sk_WOLFSSL_STRING_value(WOLF_STACK_OF(WOLFSSL_STRING)* strings, int idx) { for (; idx > 0 && strings != NULL; idx--) strings = strings->next; if (strings == NULL) return NULL; return strings->data.string; } int wolfSSL_sk_WOLFSSL_STRING_num(WOLF_STACK_OF(WOLFSSL_STRING)* strings) { if (strings) return (int)strings->num; return 0; } #endif /* WOLFSSL_NGINX || WOLFSSL_HAPROXY || OPENSSL_EXTRA || OPENSSL_ALL */ #if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || \ defined(WOLFSSL_HAPROXY) || defined(HAVE_LIGHTY) #ifdef HAVE_ALPN void wolfSSL_get0_alpn_selected(const WOLFSSL *ssl, const unsigned char **data, unsigned int *len) { word16 nameLen; if (ssl != NULL && data != NULL && len != NULL) { TLSX_ALPN_GetRequest(ssl->extensions, (void **)data, &nameLen); *len = nameLen; } } int wolfSSL_select_next_proto(unsigned char **out, unsigned char *outLen, const unsigned char *in, unsigned int inLen, const unsigned char *clientNames, unsigned int clientLen) { unsigned int i, j; byte lenIn, lenClient; if (out == NULL || outLen == NULL || in == NULL || clientNames == NULL) return OPENSSL_NPN_UNSUPPORTED; for (i = 0; i < inLen; i += lenIn) { lenIn = in[i++]; for (j = 0; j < clientLen; j += lenClient) { lenClient = clientNames[j++]; if (lenIn != lenClient) continue; if (XMEMCMP(in + i, clientNames + j, lenIn) == 0) { *out = (unsigned char *)(in + i); *outLen = lenIn; return OPENSSL_NPN_NEGOTIATED; } } } *out = (unsigned char *)clientNames + 1; *outLen = clientNames[0]; return OPENSSL_NPN_NO_OVERLAP; } void wolfSSL_CTX_set_alpn_select_cb(WOLFSSL_CTX *ctx, int (*cb) (WOLFSSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg), void *arg) { if (ctx != NULL) { ctx->alpnSelect = cb; ctx->alpnSelectArg = arg; } } void wolfSSL_CTX_set_next_protos_advertised_cb(WOLFSSL_CTX *s, int (*cb) (WOLFSSL *ssl, const unsigned char **out, unsigned int *outlen, void *arg), void *arg) { (void)s; (void)cb; (void)arg; WOLFSSL_STUB("wolfSSL_CTX_set_next_protos_advertised_cb"); } void wolfSSL_CTX_set_next_proto_select_cb(WOLFSSL_CTX *s, int (*cb) (WOLFSSL *ssl, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg), void *arg) { (void)s; (void)cb; (void)arg; WOLFSSL_STUB("wolfSSL_CTX_set_next_proto_select_cb"); } void wolfSSL_get0_next_proto_negotiated(const WOLFSSL *s, const unsigned char **data, unsigned *len) { (void)s; (void)data; (void)len; WOLFSSL_STUB("wolfSSL_get0_next_proto_negotiated"); } #endif /* HAVE_ALPN */ #endif /* WOLFSSL_NGINX / WOLFSSL_HAPROXY */ #if defined(OPENSSL_EXTRA) && defined(HAVE_ECC) int wolfSSL_CTX_set1_curves_list(WOLFSSL_CTX* ctx, const char* names) { int idx, start = 0, len; word16 curve; char name[MAX_CURVE_NAME_SZ]; if (ctx == NULL || names == NULL) { WOLFSSL_MSG("ctx or names was NULL"); return WOLFSSL_FAILURE; } /* Disable all curves so that only the ones the user wants are enabled. */ ctx->disabledCurves = 0xFFFFFFFFUL; for (idx = 1; names[idx-1] != '\0'; idx++) { if (names[idx] != ':' && names[idx] != '\0') continue; len = idx - start; if (len > MAX_CURVE_NAME_SZ - 1) return WOLFSSL_FAILURE; XMEMCPY(name, names + start, len); name[len] = 0; if ((XSTRCMP(name, "prime256v1") == 0) || (XSTRCMP(name, "secp256r1") == 0) || (XSTRCMP(name, "P-256") == 0)) { curve = WOLFSSL_ECC_SECP256R1; } else if ((XSTRCMP(name, "secp384r1") == 0) || (XSTRCMP(name, "P-384") == 0)) { curve = WOLFSSL_ECC_SECP384R1; } else if ((XSTRCMP(name, "secp521r1") == 0) || (XSTRCMP(name, "P-521") == 0)) { curve = WOLFSSL_ECC_SECP521R1; } else if (XSTRCMP(name, "X25519") == 0) { curve = WOLFSSL_ECC_X25519; } else if (XSTRCMP(name, "X448") == 0) { curve = WOLFSSL_ECC_X448; } else { #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) int ret; const ecc_set_type *eccSet; ret = wc_ecc_get_curve_idx_from_name(name); if (ret < 0) { WOLFSSL_MSG("Could not find name in set"); return WOLFSSL_FAILURE; } eccSet = wc_ecc_get_curve_params(ret); if (eccSet == NULL) { WOLFSSL_MSG("NULL set returned"); return WOLFSSL_FAILURE; } curve = GetCurveByOID(eccSet->oidSum); #else WOLFSSL_MSG("API not present to search farther using name"); return WOLFSSL_FAILURE; #endif } if (curve >= (sizeof(word32) * WOLFSSL_BIT_SIZE)) { /* shift left more than size of ctx->disabledCurves causes static * analysis report */ WOLFSSL_MSG("curve value is too large for upcoming shift"); return WOLFSSL_FAILURE; } #if defined(HAVE_SUPPORTED_CURVES) && !defined(NO_WOLFSSL_CLIENT) /* set the supported curve so client TLS extension contains only the * desired curves */ if (wolfSSL_CTX_UseSupportedCurve(ctx, curve) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("Unable to set supported curve"); return WOLFSSL_FAILURE; } #endif /* Switch the bit to off and therefore is enabled. */ ctx->disabledCurves &= ~(1U << curve); start = idx + 1; } return WOLFSSL_SUCCESS; } int wolfSSL_set1_curves_list(WOLFSSL* ssl, const char* names) { if (ssl == NULL) { return WOLFSSL_FAILURE; } return wolfSSL_CTX_set1_curves_list(ssl->ctx, names); } #endif /* OPENSSL_EXTRA && HAVE_ECC */ #ifdef OPENSSL_EXTRA /* Sets a callback for when sending and receiving protocol messages. * This callback is copied to all WOLFSSL objects created from the ctx. * * ctx WOLFSSL_CTX structure to set callback in * cb callback to use * * return WOLFSSL_SUCCESS on success and SSL_FAILURE with error case */ int wolfSSL_CTX_set_msg_callback(WOLFSSL_CTX *ctx, SSL_Msg_Cb cb) { WOLFSSL_ENTER("wolfSSL_CTX_set_msg_callback"); if (ctx == NULL) { WOLFSSL_MSG("Null ctx passed in"); return WOLFSSL_FAILURE; } ctx->protoMsgCb = cb; return WOLFSSL_SUCCESS; } /* Sets a callback for when sending and receiving protocol messages. * * ssl WOLFSSL structure to set callback in * cb callback to use * * return WOLFSSL_SUCCESS on success and SSL_FAILURE with error case */ int wolfSSL_set_msg_callback(WOLFSSL *ssl, SSL_Msg_Cb cb) { WOLFSSL_ENTER("wolfSSL_set_msg_callback"); if (ssl == NULL) { return SSL_FAILURE; } if (cb != NULL) { ssl->toInfoOn = 1; } ssl->protoMsgCb = cb; return WOLFSSL_SUCCESS; } /* set the user argument to pass to the msg callback when called * return WOLFSSL_SUCCESS on success */ int wolfSSL_CTX_set_msg_callback_arg(WOLFSSL_CTX *ctx, void* arg) { WOLFSSL_ENTER("wolfSSL_CTX_set_msg_callback_arg"); if (ctx == NULL) { WOLFSSL_MSG("Null WOLFSSL_CTX passed in"); return WOLFSSL_FAILURE; } ctx->protoMsgCtx = arg; return WOLFSSL_SUCCESS; } int wolfSSL_set_msg_callback_arg(WOLFSSL *ssl, void* arg) { WOLFSSL_ENTER("wolfSSL_set_msg_callback_arg"); if (ssl == NULL) return WOLFSSL_FAILURE; ssl->protoMsgCtx = arg; return WOLFSSL_SUCCESS; } void *wolfSSL_OPENSSL_memdup(const void *data, size_t siz, const char* file, int line) { void *ret; (void)file; (void)line; if (data == NULL || siz >= INT_MAX) return NULL; ret = OPENSSL_malloc(siz); if (ret == NULL) { return NULL; } return XMEMCPY(ret, data, siz); } void wolfSSL_OPENSSL_cleanse(void *ptr, size_t len) { if (ptr) ForceZero(ptr, (word32)len); } int wolfSSL_CTX_set_alpn_protos(WOLFSSL_CTX *ctx, const unsigned char *p, unsigned int p_len) { WOLFSSL_ENTER("wolfSSL_CTX_set_alpn_protos"); if (ctx == NULL) return BAD_FUNC_ARG; if (ctx->alpn_cli_protos != NULL) { XFREE((void*)ctx->alpn_cli_protos, ctx->heap, DYNAMIC_TYPE_OPENSSL); } ctx->alpn_cli_protos = (const unsigned char*)XMALLOC(p_len, ctx->heap, DYNAMIC_TYPE_OPENSSL); if (ctx->alpn_cli_protos == NULL) { #if defined(WOLFSSL_ERROR_CODE_OPENSSL) /* 0 on success in OpenSSL, non-0 on failure in OpenSSL * the function reverses the return value convention. */ return 1; #else return WOLFSSL_FAILURE; #endif } XMEMCPY((void*)ctx->alpn_cli_protos, p, p_len); ctx->alpn_cli_protos_len = p_len; #if defined(WOLFSSL_ERROR_CODE_OPENSSL) /* 0 on success in OpenSSL, non-0 on failure in OpenSSL * the function reverses the return value convention. */ return 0; #else return WOLFSSL_SUCCESS; #endif } #ifdef HAVE_ALPN #ifndef NO_BIO /* Sets the ALPN extension protos * * example format is * unsigned char p[] = { * 8, 'h', 't', 't', 'p', '/', '1', '.', '1' * }; * * returns WOLFSSL_SUCCESS on success */ int wolfSSL_set_alpn_protos(WOLFSSL* ssl, const unsigned char* p, unsigned int p_len) { WOLFSSL_BIO* bio; char* pt; unsigned int sz; unsigned int idx = 0; int alpn_opt = WOLFSSL_ALPN_CONTINUE_ON_MISMATCH; WOLFSSL_ENTER("wolfSSL_set_alpn_protos"); if (ssl == NULL || p_len <= 1) { #if defined(WOLFSSL_ERROR_CODE_OPENSSL) /* 0 on success in OpenSSL, non-0 on failure in OpenSSL * the function reverses the return value convention. */ return 1; #else return WOLFSSL_FAILURE; #endif } bio = wolfSSL_BIO_new(wolfSSL_BIO_s_mem()); if (bio == NULL) { #if defined(WOLFSSL_ERROR_CODE_OPENSSL) /* 0 on success in OpenSSL, non-0 on failure in OpenSSL * the function reverses the return value convention. */ return 1; #else return WOLFSSL_FAILURE; #endif } /* convert into comma separated list */ while (idx < p_len - 1) { unsigned int i; sz = p[idx++]; if (idx + sz > p_len) { WOLFSSL_MSG("Bad list format"); wolfSSL_BIO_free(bio); #if defined(WOLFSSL_ERROR_CODE_OPENSSL) /* 0 on success in OpenSSL, non-0 on failure in OpenSSL * the function reverses the return value convention. */ return 1; #else return WOLFSSL_FAILURE; #endif } if (sz > 0) { for (i = 0; i < sz; i++) { wolfSSL_BIO_write(bio, &p[idx++], 1); } if (idx < p_len - 1) wolfSSL_BIO_write(bio, ",", 1); } } wolfSSL_BIO_write(bio, "\0", 1); /* clears out all current ALPN extensions set */ TLSX_Remove(&ssl->extensions, TLSX_APPLICATION_LAYER_PROTOCOL, ssl->heap); if ((sz = wolfSSL_BIO_get_mem_data(bio, &pt)) > 0) { wolfSSL_UseALPN(ssl, pt, sz, (byte) alpn_opt); } wolfSSL_BIO_free(bio); #if defined(WOLFSSL_ERROR_CODE_OPENSSL) /* 0 on success in OpenSSL, non-0 on failure in OpenSSL * the function reverses the return value convention. */ return 0; #else return WOLFSSL_SUCCESS; #endif } #endif /* !NO_BIO */ #endif /* HAVE_ALPN */ #endif /* OPENSSL_EXTRA */ #if defined(OPENSSL_EXTRA) #ifndef NO_BIO #define WOLFSSL_BIO_INCLUDED #include "src/bio.c" #endif word32 nid2oid(int nid, int grp) { /* get OID type */ switch (grp) { /* oidHashType */ case oidHashType: switch (nid) { #ifdef WOLFSSL_MD2 case NID_md2: return MD2h; #endif #ifndef NO_MD5 case NID_md5: return MD5h; #endif #ifndef NO_SHA case NID_sha1: return SHAh; #endif case NID_sha224: return SHA224h; #ifndef NO_SHA256 case NID_sha256: return SHA256h; #endif #ifdef WOLFSSL_SHA384 case NID_sha384: return SHA384h; #endif #ifdef WOLFSSL_SHA512 case NID_sha512: return SHA512h; #endif #ifndef WOLFSSL_NOSHA3_224 case NID_sha3_224: return SHA3_224h; #endif #ifndef WOLFSSL_NOSHA3_256 case NID_sha3_256: return SHA3_256h; #endif #ifndef WOLFSSL_NOSHA3_384 case NID_sha3_384: return SHA3_384h; #endif #ifndef WOLFSSL_NOSHA3_512 case NID_sha3_512: return SHA3_512h; #endif } break; /* oidSigType */ case oidSigType: switch (nid) { #ifndef NO_DSA case NID_dsaWithSHA1: return CTC_SHAwDSA; case NID_dsa_with_SHA256: return CTC_SHA256wDSA; #endif /* NO_DSA */ #ifndef NO_RSA case NID_md2WithRSAEncryption: return CTC_MD2wRSA; case NID_md5WithRSAEncryption: return CTC_MD5wRSA; case NID_sha1WithRSAEncryption: return CTC_SHAwRSA; case NID_sha224WithRSAEncryption: return CTC_SHA224wRSA; case NID_sha256WithRSAEncryption: return CTC_SHA256wRSA; case NID_sha384WithRSAEncryption: return CTC_SHA384wRSA; case NID_sha512WithRSAEncryption: return CTC_SHA512wRSA; #ifdef WOLFSSL_SHA3 case NID_RSA_SHA3_224: return CTC_SHA3_224wRSA; case NID_RSA_SHA3_256: return CTC_SHA3_256wRSA; case NID_RSA_SHA3_384: return CTC_SHA3_384wRSA; case NID_RSA_SHA3_512: return CTC_SHA3_512wRSA; #endif #endif /* NO_RSA */ #ifdef HAVE_ECC case NID_ecdsa_with_SHA1: return CTC_SHAwECDSA; case NID_ecdsa_with_SHA224: return CTC_SHA224wECDSA; case NID_ecdsa_with_SHA256: return CTC_SHA256wECDSA; case NID_ecdsa_with_SHA384: return CTC_SHA384wECDSA; case NID_ecdsa_with_SHA512: return CTC_SHA512wECDSA; #ifdef WOLFSSL_SHA3 case NID_ecdsa_with_SHA3_224: return CTC_SHA3_224wECDSA; case NID_ecdsa_with_SHA3_256: return CTC_SHA3_256wECDSA; case NID_ecdsa_with_SHA3_384: return CTC_SHA3_384wECDSA; case NID_ecdsa_with_SHA3_512: return CTC_SHA3_512wECDSA; #endif #endif /* HAVE_ECC */ } break; /* oidKeyType */ case oidKeyType: switch (nid) { #ifndef NO_DSA case NID_dsa: return DSAk; #endif /* NO_DSA */ #ifndef NO_RSA case NID_rsaEncryption: return RSAk; #endif /* NO_RSA */ #ifdef HAVE_ECC case NID_X9_62_id_ecPublicKey: return ECDSAk; #endif /* HAVE_ECC */ } break; #ifdef HAVE_ECC case oidCurveType: switch (nid) { case NID_X9_62_prime192v1: return ECC_SECP192R1_OID; case NID_X9_62_prime192v2: return ECC_PRIME192V2_OID; case NID_X9_62_prime192v3: return ECC_PRIME192V3_OID; case NID_X9_62_prime239v1: return ECC_PRIME239V1_OID; case NID_X9_62_prime239v2: return ECC_PRIME239V2_OID; case NID_X9_62_prime239v3: return ECC_PRIME239V3_OID; case NID_X9_62_prime256v1: return ECC_SECP256R1_OID; case NID_secp112r1: return ECC_SECP112R1_OID; case NID_secp112r2: return ECC_SECP112R2_OID; case NID_secp128r1: return ECC_SECP128R1_OID; case NID_secp128r2: return ECC_SECP128R2_OID; case NID_secp160r1: return ECC_SECP160R1_OID; case NID_secp160r2: return ECC_SECP160R2_OID; case NID_secp224r1: return ECC_SECP224R1_OID; case NID_secp384r1: return ECC_SECP384R1_OID; case NID_secp521r1: return ECC_SECP521R1_OID; case NID_secp160k1: return ECC_SECP160K1_OID; case NID_secp192k1: return ECC_SECP192K1_OID; case NID_secp224k1: return ECC_SECP224K1_OID; case NID_secp256k1: return ECC_SECP256K1_OID; case NID_brainpoolP160r1: return ECC_BRAINPOOLP160R1_OID; case NID_brainpoolP192r1: return ECC_BRAINPOOLP192R1_OID; case NID_brainpoolP224r1: return ECC_BRAINPOOLP224R1_OID; case NID_brainpoolP256r1: return ECC_BRAINPOOLP256R1_OID; case NID_brainpoolP320r1: return ECC_BRAINPOOLP320R1_OID; case NID_brainpoolP384r1: return ECC_BRAINPOOLP384R1_OID; case NID_brainpoolP512r1: return ECC_BRAINPOOLP512R1_OID; } break; #endif /* HAVE_ECC */ /* oidBlkType */ case oidBlkType: switch (nid) { #ifdef WOLFSSL_AES_128 case AES128CBCb: return AES128CBCb; #endif #ifdef WOLFSSL_AES_192 case AES192CBCb: return AES192CBCb; #endif #ifdef WOLFSSL_AES_256 case AES256CBCb: return AES256CBCb; #endif #ifndef NO_DES3 case NID_des: return DESb; case NID_des3: return DES3b; #endif } break; #ifdef HAVE_OCSP case oidOcspType: switch (nid) { case NID_id_pkix_OCSP_basic: return OCSP_BASIC_OID; case OCSP_NONCE_OID: return OCSP_NONCE_OID; } break; #endif /* HAVE_OCSP */ /* oidCertExtType */ case oidCertExtType: switch (nid) { case NID_basic_constraints: return BASIC_CA_OID; case NID_subject_alt_name: return ALT_NAMES_OID; case NID_crl_distribution_points: return CRL_DIST_OID; case NID_info_access: return AUTH_INFO_OID; case NID_authority_key_identifier: return AUTH_KEY_OID; case NID_subject_key_identifier: return SUBJ_KEY_OID; case NID_inhibit_any_policy: return INHIBIT_ANY_OID; case NID_key_usage: return KEY_USAGE_OID; case NID_name_constraints: return NAME_CONS_OID; case NID_certificate_policies: return CERT_POLICY_OID; case NID_ext_key_usage: return EXT_KEY_USAGE_OID; } break; /* oidCertAuthInfoType */ case oidCertAuthInfoType: switch (nid) { case NID_ad_OCSP: return AIA_OCSP_OID; case NID_ad_ca_issuers: return AIA_CA_ISSUER_OID; } break; /* oidCertPolicyType */ case oidCertPolicyType: switch (nid) { case NID_any_policy: return CP_ANY_OID; } break; /* oidCertAltNameType */ case oidCertAltNameType: switch (nid) { case NID_hw_name_oid: return HW_NAME_OID; } break; /* oidCertKeyUseType */ case oidCertKeyUseType: switch (nid) { case NID_anyExtendedKeyUsage: return EKU_ANY_OID; case EKU_SERVER_AUTH_OID: return EKU_SERVER_AUTH_OID; case EKU_CLIENT_AUTH_OID: return EKU_CLIENT_AUTH_OID; case EKU_OCSP_SIGN_OID: return EKU_OCSP_SIGN_OID; } break; /* oidKdfType */ case oidKdfType: switch (nid) { case PBKDF2_OID: return PBKDF2_OID; } break; /* oidPBEType */ case oidPBEType: switch (nid) { case PBE_SHA1_RC4_128: return PBE_SHA1_RC4_128; case PBE_SHA1_DES: return PBE_SHA1_DES; case PBE_SHA1_DES3: return PBE_SHA1_DES3; } break; /* oidKeyWrapType */ case oidKeyWrapType: switch (nid) { #ifdef WOLFSSL_AES_128 case AES128_WRAP: return AES128_WRAP; #endif #ifdef WOLFSSL_AES_192 case AES192_WRAP: return AES192_WRAP; #endif #ifdef WOLFSSL_AES_256 case AES256_WRAP: return AES256_WRAP; #endif } break; /* oidCmsKeyAgreeType */ case oidCmsKeyAgreeType: switch (nid) { #ifndef NO_SHA case dhSinglePass_stdDH_sha1kdf_scheme: return dhSinglePass_stdDH_sha1kdf_scheme; #endif #ifdef WOLFSSL_SHA224 case dhSinglePass_stdDH_sha224kdf_scheme: return dhSinglePass_stdDH_sha224kdf_scheme; #endif #ifndef NO_SHA256 case dhSinglePass_stdDH_sha256kdf_scheme: return dhSinglePass_stdDH_sha256kdf_scheme; #endif #ifdef WOLFSSL_SHA384 case dhSinglePass_stdDH_sha384kdf_scheme: return dhSinglePass_stdDH_sha384kdf_scheme; #endif #ifdef WOLFSSL_SHA512 case dhSinglePass_stdDH_sha512kdf_scheme: return dhSinglePass_stdDH_sha512kdf_scheme; #endif } break; default: WOLFSSL_MSG("NID not in table"); /* MSVC warns without the cast */ return (word32)-1; } /* MSVC warns without the cast */ return (word32)-1; } int oid2nid(word32 oid, int grp) { size_t i; /* get OID type */ switch (grp) { /* oidHashType */ case oidHashType: switch (oid) { #ifdef WOLFSSL_MD2 case MD2h: return NID_md2; #endif #ifndef NO_MD5 case MD5h: return NID_md5; #endif #ifndef NO_SHA case SHAh: return NID_sha1; #endif case SHA224h: return NID_sha224; #ifndef NO_SHA256 case SHA256h: return NID_sha256; #endif #ifdef WOLFSSL_SHA384 case SHA384h: return NID_sha384; #endif #ifdef WOLFSSL_SHA512 case SHA512h: return NID_sha512; #endif } break; /* oidSigType */ case oidSigType: switch (oid) { #ifndef NO_DSA case CTC_SHAwDSA: return NID_dsaWithSHA1; case CTC_SHA256wDSA: return NID_dsa_with_SHA256; #endif /* NO_DSA */ #ifndef NO_RSA case CTC_MD2wRSA: return NID_md2WithRSAEncryption; case CTC_MD5wRSA: return NID_md5WithRSAEncryption; case CTC_SHAwRSA: return NID_sha1WithRSAEncryption; case CTC_SHA224wRSA: return NID_sha224WithRSAEncryption; case CTC_SHA256wRSA: return NID_sha256WithRSAEncryption; case CTC_SHA384wRSA: return NID_sha384WithRSAEncryption; case CTC_SHA512wRSA: return NID_sha512WithRSAEncryption; #ifdef WOLFSSL_SHA3 case CTC_SHA3_224wRSA: return NID_RSA_SHA3_224; case CTC_SHA3_256wRSA: return NID_RSA_SHA3_256; case CTC_SHA3_384wRSA: return NID_RSA_SHA3_384; case CTC_SHA3_512wRSA: return NID_RSA_SHA3_512; #endif #endif /* NO_RSA */ #ifdef HAVE_ECC case CTC_SHAwECDSA: return NID_ecdsa_with_SHA1; case CTC_SHA224wECDSA: return NID_ecdsa_with_SHA224; case CTC_SHA256wECDSA: return NID_ecdsa_with_SHA256; case CTC_SHA384wECDSA: return NID_ecdsa_with_SHA384; case CTC_SHA512wECDSA: return NID_ecdsa_with_SHA512; #ifdef WOLFSSL_SHA3 case CTC_SHA3_224wECDSA: return NID_ecdsa_with_SHA3_224; case CTC_SHA3_256wECDSA: return NID_ecdsa_with_SHA3_256; case CTC_SHA3_384wECDSA: return NID_ecdsa_with_SHA3_384; case CTC_SHA3_512wECDSA: return NID_ecdsa_with_SHA3_512; #endif #endif /* HAVE_ECC */ } break; /* oidKeyType */ case oidKeyType: switch (oid) { #ifndef NO_DSA case DSAk: return NID_dsa; #endif /* NO_DSA */ #ifndef NO_RSA case RSAk: return NID_rsaEncryption; #endif /* NO_RSA */ #ifdef HAVE_ECC case ECDSAk: return NID_X9_62_id_ecPublicKey; #endif /* HAVE_ECC */ } break; #ifdef HAVE_ECC case oidCurveType: switch (oid) { case ECC_SECP192R1_OID: return NID_X9_62_prime192v1; case ECC_PRIME192V2_OID: return NID_X9_62_prime192v2; case ECC_PRIME192V3_OID: return NID_X9_62_prime192v3; case ECC_PRIME239V1_OID: return NID_X9_62_prime239v1; case ECC_PRIME239V2_OID: return NID_X9_62_prime239v2; case ECC_PRIME239V3_OID: return NID_X9_62_prime239v3; case ECC_SECP256R1_OID: return NID_X9_62_prime256v1; case ECC_SECP112R1_OID: return NID_secp112r1; case ECC_SECP112R2_OID: return NID_secp112r2; case ECC_SECP128R1_OID: return NID_secp128r1; case ECC_SECP128R2_OID: return NID_secp128r2; case ECC_SECP160R1_OID: return NID_secp160r1; case ECC_SECP160R2_OID: return NID_secp160r2; case ECC_SECP224R1_OID: return NID_secp224r1; case ECC_SECP384R1_OID: return NID_secp384r1; case ECC_SECP521R1_OID: return NID_secp521r1; case ECC_SECP160K1_OID: return NID_secp160k1; case ECC_SECP192K1_OID: return NID_secp192k1; case ECC_SECP224K1_OID: return NID_secp224k1; case ECC_SECP256K1_OID: return NID_secp256k1; case ECC_BRAINPOOLP160R1_OID: return NID_brainpoolP160r1; case ECC_BRAINPOOLP192R1_OID: return NID_brainpoolP192r1; case ECC_BRAINPOOLP224R1_OID: return NID_brainpoolP224r1; case ECC_BRAINPOOLP256R1_OID: return NID_brainpoolP256r1; case ECC_BRAINPOOLP320R1_OID: return NID_brainpoolP320r1; case ECC_BRAINPOOLP384R1_OID: return NID_brainpoolP384r1; case ECC_BRAINPOOLP512R1_OID: return NID_brainpoolP512r1; } break; #endif /* HAVE_ECC */ /* oidBlkType */ case oidBlkType: switch (oid) { #ifdef WOLFSSL_AES_128 case AES128CBCb: return AES128CBCb; #endif #ifdef WOLFSSL_AES_192 case AES192CBCb: return AES192CBCb; #endif #ifdef WOLFSSL_AES_256 case AES256CBCb: return AES256CBCb; #endif #ifndef NO_DES3 case DESb: return NID_des; case DES3b: return NID_des3; #endif } break; #ifdef HAVE_OCSP case oidOcspType: switch (oid) { case OCSP_BASIC_OID: return NID_id_pkix_OCSP_basic; case OCSP_NONCE_OID: return OCSP_NONCE_OID; } break; #endif /* HAVE_OCSP */ /* oidCertExtType */ case oidCertExtType: switch (oid) { case BASIC_CA_OID: return NID_basic_constraints; case ALT_NAMES_OID: return NID_subject_alt_name; case CRL_DIST_OID: return NID_crl_distribution_points; case AUTH_INFO_OID: return NID_info_access; case AUTH_KEY_OID: return NID_authority_key_identifier; case SUBJ_KEY_OID: return NID_subject_key_identifier; case INHIBIT_ANY_OID: return NID_inhibit_any_policy; case KEY_USAGE_OID: return NID_key_usage; case NAME_CONS_OID: return NID_name_constraints; case CERT_POLICY_OID: return NID_certificate_policies; case EXT_KEY_USAGE_OID: return NID_ext_key_usage; } break; /* oidCertAuthInfoType */ case oidCertAuthInfoType: switch (oid) { case AIA_OCSP_OID: return NID_ad_OCSP; case AIA_CA_ISSUER_OID: return NID_ad_ca_issuers; } break; /* oidCertPolicyType */ case oidCertPolicyType: switch (oid) { case CP_ANY_OID: return NID_any_policy; } break; /* oidCertAltNameType */ case oidCertAltNameType: switch (oid) { case HW_NAME_OID: return NID_hw_name_oid; } break; /* oidCertKeyUseType */ case oidCertKeyUseType: switch (oid) { case EKU_ANY_OID: return NID_anyExtendedKeyUsage; case EKU_SERVER_AUTH_OID: return EKU_SERVER_AUTH_OID; case EKU_CLIENT_AUTH_OID: return EKU_CLIENT_AUTH_OID; case EKU_OCSP_SIGN_OID: return EKU_OCSP_SIGN_OID; } break; /* oidKdfType */ case oidKdfType: switch (oid) { case PBKDF2_OID: return PBKDF2_OID; } break; /* oidPBEType */ case oidPBEType: switch (oid) { case PBE_SHA1_RC4_128: return PBE_SHA1_RC4_128; case PBE_SHA1_DES: return PBE_SHA1_DES; case PBE_SHA1_DES3: return PBE_SHA1_DES3; } break; /* oidKeyWrapType */ case oidKeyWrapType: switch (oid) { #ifdef WOLFSSL_AES_128 case AES128_WRAP: return AES128_WRAP; #endif #ifdef WOLFSSL_AES_192 case AES192_WRAP: return AES192_WRAP; #endif #ifdef WOLFSSL_AES_256 case AES256_WRAP: return AES256_WRAP; #endif } break; /* oidCmsKeyAgreeType */ case oidCmsKeyAgreeType: switch (oid) { #ifndef NO_SHA case dhSinglePass_stdDH_sha1kdf_scheme: return dhSinglePass_stdDH_sha1kdf_scheme; #endif #ifdef WOLFSSL_SHA224 case dhSinglePass_stdDH_sha224kdf_scheme: return dhSinglePass_stdDH_sha224kdf_scheme; #endif #ifndef NO_SHA256 case dhSinglePass_stdDH_sha256kdf_scheme: return dhSinglePass_stdDH_sha256kdf_scheme; #endif #ifdef WOLFSSL_SHA384 case dhSinglePass_stdDH_sha384kdf_scheme: return dhSinglePass_stdDH_sha384kdf_scheme; #endif #ifdef WOLFSSL_SHA512 case dhSinglePass_stdDH_sha512kdf_scheme: return dhSinglePass_stdDH_sha512kdf_scheme; #endif } break; #ifdef WOLFSSL_CERT_REQ case oidCsrAttrType: switch (oid) { case PKCS9_CONTENT_TYPE_OID: return NID_pkcs9_contentType; case CHALLENGE_PASSWORD_OID: return NID_pkcs9_challengePassword; case SERIAL_NUMBER_OID: return NID_serialNumber; case USER_ID_OID: return NID_userId; } break; #endif default: WOLFSSL_MSG("NID not in table"); } /* If not found in above switch then try the table */ for (i = 0; i < WOLFSSL_OBJECT_INFO_SZ; i++) { if (wolfssl_object_info[i].id == (int)oid) { return wolfssl_object_info[i].nid; } } return -1; } /* when calling SetIndividualInternal, mpi should be cleared by caller if no * longer used. ie mp_free(mpi). This is to free data when fastmath is * disabled since a copy of mpi is made by this function and placed into bn. */ int SetIndividualInternal(WOLFSSL_BIGNUM* bn, mp_int* mpi) { WOLFSSL_MSG("Entering SetIndividualInternal"); if (bn == NULL || bn->internal == NULL) { WOLFSSL_MSG("bn NULL error"); return WOLFSSL_FATAL_ERROR; } if (mpi == NULL) { WOLFSSL_MSG("mpi NULL error"); return WOLFSSL_FATAL_ERROR; } if (mp_copy((mp_int*)bn->internal, mpi) != MP_OKAY) { WOLFSSL_MSG("mp_copy error"); return WOLFSSL_FATAL_ERROR; } return WOLFSSL_SUCCESS; } #ifndef NO_ASN WOLFSSL_BIGNUM *wolfSSL_ASN1_INTEGER_to_BN(const WOLFSSL_ASN1_INTEGER *ai, WOLFSSL_BIGNUM *bn) { #ifdef WOLFSSL_SMALL_STACK mp_int* mpi = NULL; #else mp_int mpi[1]; #endif word32 idx = 0; int ret; WOLFSSL_ENTER("wolfSSL_ASN1_INTEGER_to_BN"); if (ai == NULL) { return NULL; } #ifdef WOLFSSL_SMALL_STACK mpi = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_BIGINT); if (mpi == NULL) { return NULL; } #endif ret = GetInt(mpi, ai->data, &idx, ai->dataMax); if (ret != 0) { #if defined(WOLFSSL_QT) || defined(WOLFSSL_HAPROXY) ret = mp_init(mpi); /* must init mpi */ if (ret != MP_OKAY) { #ifdef WOLFSSL_SMALL_STACK XFREE(mpi, NULL, DYNAMIC_TYPE_BIGINT); #endif return NULL; } /* Serial number in QT starts at index 0 of data */ if (mp_read_unsigned_bin(mpi, (byte*)ai->data, ai->length) != 0) { mp_clear(mpi); #ifdef WOLFSSL_SMALL_STACK XFREE(mpi, NULL, DYNAMIC_TYPE_BIGINT); #endif return NULL; } #else /* expecting ASN1 format for INTEGER */ WOLFSSL_LEAVE("wolfSSL_ASN1_INTEGER_to_BN", ret); #ifdef WOLFSSL_SMALL_STACK XFREE(mpi, NULL, DYNAMIC_TYPE_BIGINT); #endif return NULL; #endif } /* mp_clear needs called because mpi is copied and causes memory leak with * --disable-fastmath */ ret = SetIndividualExternal(&bn, mpi); mp_clear(mpi); #ifdef WOLFSSL_SMALL_STACK XFREE(mpi, NULL, DYNAMIC_TYPE_BIGINT); #endif if (ret != WOLFSSL_SUCCESS) { return NULL; } return bn; } #endif /* !NO_ASN */ /* frees all nodes in the current threads error queue * * id thread id. ERR_remove_state is depreciated and id is ignored. The * current threads queue will be free'd. */ void wolfSSL_ERR_remove_state(unsigned long id) { WOLFSSL_ENTER("wolfSSL_ERR_remove_state"); (void)id; if (wc_ERR_remove_state() != 0) { WOLFSSL_MSG("Error with removing the state"); } } WOLFSSL_BN_CTX* wolfSSL_BN_CTX_new(void) { static int ctx; /* wolfcrypt doesn't now need ctx */ WOLFSSL_MSG("wolfSSL_BN_CTX_new"); return (WOLFSSL_BN_CTX*)&ctx; } void wolfSSL_BN_CTX_init(WOLFSSL_BN_CTX* ctx) { (void)ctx; WOLFSSL_MSG("wolfSSL_BN_CTX_init"); } void wolfSSL_BN_CTX_free(WOLFSSL_BN_CTX* ctx) { (void)ctx; WOLFSSL_MSG("wolfSSL_BN_CTX_free"); /* do free since static ctx that does nothing */ } /* WOLFSSL_SUCCESS on ok */ int wolfSSL_BN_sub(WOLFSSL_BIGNUM* r, const WOLFSSL_BIGNUM* a, const WOLFSSL_BIGNUM* b) { WOLFSSL_MSG("wolfSSL_BN_sub"); if (r == NULL || a == NULL || b == NULL) return 0; if (mp_sub((mp_int*)a->internal,(mp_int*)b->internal, (mp_int*)r->internal) == MP_OKAY) return WOLFSSL_SUCCESS; WOLFSSL_MSG("wolfSSL_BN_sub mp_sub failed"); return 0; } WOLFSSL_API int wolfSSL_BN_mul(WOLFSSL_BIGNUM *r, WOLFSSL_BIGNUM *a, WOLFSSL_BIGNUM *b, WOLFSSL_BN_CTX *ctx) { int ret = WOLFSSL_SUCCESS; (void)ctx; WOLFSSL_ENTER("wolfSSL_BN_mul"); if (r == NULL || a == NULL || b == NULL || r->internal == NULL || a->internal == NULL || b->internal == NULL) { ret = WOLFSSL_FAILURE; } if (ret == WOLFSSL_SUCCESS) { ret = mp_mul((mp_int*)a->internal, (mp_int*)b->internal, (mp_int*)r->internal); if (ret == MP_OKAY) { ret = WOLFSSL_SUCCESS; } else { ret = WOLFSSL_FAILURE; } } WOLFSSL_LEAVE("wolfSSL_BN_mul", ret); return ret; } #ifndef WOLFSSL_SP_MATH int wolfSSL_BN_div(WOLFSSL_BIGNUM* dv, WOLFSSL_BIGNUM* rem, const WOLFSSL_BIGNUM* a, const WOLFSSL_BIGNUM* d, WOLFSSL_BN_CTX* ctx) { int ret = WOLFSSL_SUCCESS; (void)ctx; WOLFSSL_ENTER("wolfSSL_BN_div"); if (dv == NULL || rem == NULL || a == NULL || d == NULL || dv->internal == NULL || rem->internal == NULL || a->internal == NULL || d->internal == NULL) { ret = WOLFSSL_FAILURE; } if (ret == WOLFSSL_SUCCESS) { ret = mp_div((mp_int*)a->internal, (mp_int*)d->internal, (mp_int*)dv->internal, (mp_int*)rem->internal); if (ret == MP_OKAY) { ret = WOLFSSL_SUCCESS; } else { ret = WOLFSSL_FAILURE; } } WOLFSSL_LEAVE("wolfSSL_BN_div", ret); return ret; } #endif #if !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN) /* Needed to get mp_gcd. */ int wolfSSL_BN_gcd(WOLFSSL_BIGNUM* r, WOLFSSL_BIGNUM* a, WOLFSSL_BIGNUM* b, WOLFSSL_BN_CTX* ctx) { int ret = WOLFSSL_SUCCESS; (void)ctx; WOLFSSL_ENTER("wolfSSL_BN_gcd"); if (r == NULL || a == NULL || b == NULL || r->internal == NULL || a->internal == NULL || b->internal == NULL) { ret = WOLFSSL_FAILURE; } if (ret == WOLFSSL_SUCCESS) { ret = mp_gcd((mp_int*)a->internal, (mp_int*)b->internal, (mp_int*)r->internal); if (ret == MP_OKAY) { ret = WOLFSSL_SUCCESS; } else { ret = WOLFSSL_FAILURE; } } WOLFSSL_LEAVE("wolfSSL_BN_gcd", ret); return ret; } #endif /* !NO_RSA && WOLFSSL_KEY_GEN */ /* WOLFSSL_SUCCESS on ok */ int wolfSSL_BN_mod(WOLFSSL_BIGNUM* r, const WOLFSSL_BIGNUM* a, const WOLFSSL_BIGNUM* b, const WOLFSSL_BN_CTX* c) { (void)c; WOLFSSL_MSG("wolfSSL_BN_mod"); if (r == NULL || a == NULL || b == NULL) return 0; if (mp_mod((mp_int*)a->internal,(mp_int*)b->internal, (mp_int*)r->internal) == MP_OKAY) return WOLFSSL_SUCCESS; WOLFSSL_MSG("wolfSSL_BN_mod mp_mod failed"); return 0; } /* r = (a^p) % m */ int wolfSSL_BN_mod_exp(WOLFSSL_BIGNUM *r, const WOLFSSL_BIGNUM *a, const WOLFSSL_BIGNUM *p, const WOLFSSL_BIGNUM *m, WOLFSSL_BN_CTX *ctx) { int ret; WOLFSSL_ENTER("wolfSSL_BN_mod_exp"); (void) ctx; if (r == NULL || a == NULL || p == NULL || m == NULL) { WOLFSSL_MSG("Bad Argument"); return WOLFSSL_FAILURE; } if ((ret = mp_exptmod((mp_int*)a->internal,(mp_int*)p->internal, (mp_int*)m->internal, (mp_int*)r->internal)) == MP_OKAY) { return WOLFSSL_SUCCESS; } WOLFSSL_LEAVE("wolfSSL_BN_mod_exp", ret); (void)ret; return WOLFSSL_FAILURE; } /* r = (a * p) % m */ int wolfSSL_BN_mod_mul(WOLFSSL_BIGNUM *r, const WOLFSSL_BIGNUM *a, const WOLFSSL_BIGNUM *p, const WOLFSSL_BIGNUM *m, WOLFSSL_BN_CTX *ctx) { int ret; WOLFSSL_ENTER("wolfSSL_BN_mod_mul"); (void) ctx; if (r == NULL || a == NULL || p == NULL || m == NULL) { WOLFSSL_MSG("Bad Argument"); return SSL_FAILURE; } if ((ret = mp_mulmod((mp_int*)a->internal,(mp_int*)p->internal, (mp_int*)m->internal, (mp_int*)r->internal)) == MP_OKAY) { return WOLFSSL_SUCCESS; } WOLFSSL_LEAVE("wolfSSL_BN_mod_mul", ret); (void)ret; return SSL_FAILURE; } const WOLFSSL_BIGNUM* wolfSSL_BN_value_one(void) { WOLFSSL_MSG("wolfSSL_BN_value_one"); if (bn_one == NULL) { bn_one = wolfSSL_BN_new(); if (bn_one) { if (mp_set_int((mp_int*)bn_one->internal, 1) != MP_OKAY) { /* handle error by freeing BN and returning NULL */ wolfSSL_BN_free(bn_one); bn_one = NULL; } } } return bn_one; } /* return compliant with OpenSSL * size of BIGNUM in bytes, 0 if error */ int wolfSSL_BN_num_bytes(const WOLFSSL_BIGNUM* bn) { WOLFSSL_ENTER("wolfSSL_BN_num_bytes"); if (bn == NULL || bn->internal == NULL) return WOLFSSL_FAILURE; return mp_unsigned_bin_size((mp_int*)bn->internal); } /* return compliant with OpenSSL * size of BIGNUM in bits, 0 if error */ int wolfSSL_BN_num_bits(const WOLFSSL_BIGNUM* bn) { WOLFSSL_ENTER("wolfSSL_BN_num_bits"); if (bn == NULL || bn->internal == NULL) return WOLFSSL_FAILURE; return mp_count_bits((mp_int*)bn->internal); } int wolfSSL_BN_is_negative(const WOLFSSL_BIGNUM* bn) { if (bn == NULL) return WOLFSSL_FAILURE; return mp_isneg((mp_int*)bn->internal); } WOLFSSL_API void wolfSSL_BN_zero(WOLFSSL_BIGNUM* bn) { if (bn == NULL || bn->internal == NULL) { return; } mp_zero((mp_int*)bn->internal); } WOLFSSL_API int wolfSSL_BN_one(WOLFSSL_BIGNUM* bn) { int ret = WOLFSSL_SUCCESS; if (bn == NULL || bn->internal == NULL) { return WOLFSSL_FAILURE; } if (ret == WOLFSSL_SUCCESS) { ret = wolfSSL_BN_set_word(bn, 1); } return ret; } /* return compliant with OpenSSL * 1 if BIGNUM is zero, 0 else */ int wolfSSL_BN_is_zero(const WOLFSSL_BIGNUM* bn) { WOLFSSL_MSG("wolfSSL_BN_is_zero"); if (bn == NULL || bn->internal == NULL) return WOLFSSL_FAILURE; if (mp_iszero((mp_int*)bn->internal) == MP_YES) return WOLFSSL_SUCCESS; return WOLFSSL_FAILURE; } /* return compliant with OpenSSL * 1 if BIGNUM is one, 0 else */ int wolfSSL_BN_is_one(const WOLFSSL_BIGNUM* bn) { WOLFSSL_MSG("wolfSSL_BN_is_one"); if (bn == NULL || bn->internal == NULL) return WOLFSSL_FAILURE; if (mp_cmp_d((mp_int*)bn->internal, 1) == MP_EQ) return WOLFSSL_SUCCESS; return WOLFSSL_FAILURE; } /* return compliant with OpenSSL * 1 if BIGNUM is odd, 0 else */ int wolfSSL_BN_is_odd(const WOLFSSL_BIGNUM* bn) { WOLFSSL_MSG("wolfSSL_BN_is_odd"); if (bn == NULL || bn->internal == NULL) return WOLFSSL_FAILURE; if (mp_isodd((mp_int*)bn->internal) == MP_YES) return WOLFSSL_SUCCESS; return WOLFSSL_FAILURE; } /* return compliant with OpenSSL * 1 if BIGNUM is word, 0 else */ int wolfSSL_BN_is_word(const WOLFSSL_BIGNUM* bn, WOLFSSL_BN_ULONG w) { WOLFSSL_MSG("wolfSSL_BN_is_word"); if (bn == NULL || bn->internal == NULL) { WOLFSSL_MSG("bn NULL error"); return WOLFSSL_FAILURE; } if (w <= (WOLFSSL_BN_ULONG)MP_MASK) { if (mp_isword((mp_int*)bn->internal, (mp_digit)w) == MP_YES) { return WOLFSSL_SUCCESS; } } else { int ret; mp_int w_mp; if (mp_init(&w_mp) != MP_OKAY) return WOLFSSL_FAILURE; if (mp_set_int(&w_mp, w) != MP_OKAY) return WOLFSSL_FAILURE; ret = mp_cmp((mp_int *)bn->internal, &w_mp); mp_free(&w_mp); if (ret == MP_EQ) return WOLFSSL_SUCCESS; } return WOLFSSL_FAILURE; } /* return compliant with OpenSSL * -1 if a < b, 0 if a == b and 1 if a > b */ int wolfSSL_BN_cmp(const WOLFSSL_BIGNUM* a, const WOLFSSL_BIGNUM* b) { int ret; WOLFSSL_MSG("wolfSSL_BN_cmp"); if (a == NULL || a->internal == NULL || b == NULL || b->internal == NULL) return WOLFSSL_FATAL_ERROR; ret = mp_cmp((mp_int*)a->internal, (mp_int*)b->internal); return (ret == MP_EQ ? 0 : (ret == MP_GT ? 1 : -1)); } /* return compliant with OpenSSL * length of BIGNUM in bytes, -1 if error */ int wolfSSL_BN_bn2bin(const WOLFSSL_BIGNUM* bn, unsigned char* r) { WOLFSSL_MSG("wolfSSL_BN_bn2bin"); if (bn == NULL || bn->internal == NULL) { WOLFSSL_MSG("NULL bn error"); return WOLFSSL_FATAL_ERROR; } if (r == NULL) return mp_unsigned_bin_size((mp_int*)bn->internal); if (mp_to_unsigned_bin((mp_int*)bn->internal, r) != MP_OKAY) { WOLFSSL_MSG("mp_to_unsigned_bin error"); return WOLFSSL_FATAL_ERROR; } return mp_unsigned_bin_size((mp_int*)bn->internal); } WOLFSSL_BIGNUM* wolfSSL_BN_bin2bn(const unsigned char* str, int len, WOLFSSL_BIGNUM* ret) { int weOwn = 0; WOLFSSL_MSG("wolfSSL_BN_bin2bn"); /* if ret is null create a BN */ if (ret == NULL) { ret = wolfSSL_BN_new(); weOwn = 1; if (ret == NULL) return NULL; } /* check ret and ret->internal then read in value */ if (ret && ret->internal) { if (mp_read_unsigned_bin((mp_int*)ret->internal, str, len) != 0) { WOLFSSL_MSG("mp_read_unsigned_bin failure"); if (weOwn) wolfSSL_BN_free(ret); return NULL; } } else { /* This may be overly defensive */ if (weOwn) wolfSSL_BN_free(ret); return NULL; } return ret; } /* return compliant with OpenSSL * 1 if success, 0 if error */ #ifndef NO_WOLFSSL_STUB int wolfSSL_mask_bits(WOLFSSL_BIGNUM* bn, int n) { (void)bn; (void)n; WOLFSSL_ENTER("wolfSSL_BN_mask_bits"); WOLFSSL_STUB("BN_mask_bits"); return SSL_FAILURE; } #endif /* WOLFSSL_SUCCESS on ok */ int wolfSSL_BN_rand(WOLFSSL_BIGNUM* bn, int bits, int top, int bottom) { int ret = WOLFSSL_SUCCESS; int len = (bits + 7) / 8; WC_RNG* rng = &globalRNG; byte* buff = NULL; WOLFSSL_ENTER("wolfSSL_BN_rand"); if ((bn == NULL || bn->internal == NULL) || bits < 0 || (bits == 0 && (bottom != 0 || top != -1)) || (bits == 1 && top > 0)) { WOLFSSL_MSG("Bad argument"); ret = WOLFSSL_FAILURE; } if (ret == WOLFSSL_SUCCESS) { if (len == 0) { mp_zero((mp_int*)bn->internal); } else { buff = (byte*)XMALLOC(len, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (buff == NULL) { WOLFSSL_MSG("Failed to allocate buffer."); XFREE(buff, NULL, DYNAMIC_TYPE_TMP_BUFFER); ret = WOLFSSL_FAILURE; } if (ret == WOLFSSL_SUCCESS && initGlobalRNG == 0 && wolfSSL_RAND_Init() != WOLFSSL_SUCCESS) { WOLFSSL_MSG("Failed to use global RNG."); ret = WOLFSSL_FAILURE; } if (ret == WOLFSSL_SUCCESS && wc_RNG_GenerateBlock(rng, buff, len) != 0) { WOLFSSL_MSG("wc_RNG_GenerateBlock failed"); ret = WOLFSSL_FAILURE; } if (ret == WOLFSSL_SUCCESS && mp_read_unsigned_bin((mp_int*)bn->internal,buff,len) != MP_OKAY) { WOLFSSL_MSG("mp_read_unsigned_bin failed"); ret = WOLFSSL_FAILURE; } if (ret == WOLFSSL_SUCCESS) { /* Truncate to requested bit length. */ mp_rshb((mp_int*)bn->internal, 8 - (bits % 8)); if (top == 0) { if (mp_set_bit((mp_int*)bn->internal, bits - 1) != MP_OKAY) { WOLFSSL_MSG("Failed to set top bit"); ret = WOLFSSL_FAILURE; } } else if (top > 0) { if (mp_set_bit((mp_int*)bn->internal, bits - 1) != MP_OKAY || mp_set_bit((mp_int*)bn->internal, bits - 2) != MP_OKAY) { WOLFSSL_MSG("Failed to set top 2 bits"); ret = WOLFSSL_FAILURE; } } } if (ret == WOLFSSL_SUCCESS && bottom && mp_set_bit((mp_int*)bn->internal, 0) != MP_OKAY) { WOLFSSL_MSG("Failed to set 0th bit"); ret = WOLFSSL_FAILURE; } if (buff != NULL) { XFREE(buff, NULL, DYNAMIC_TYPE_TMP_BUFFER); } } } WOLFSSL_LEAVE("wolfSSL_BN_rand", ret); return ret; } /** * N = length of range input var * Generate N-bit length numbers until generated number is less than range * @param r Output number * @param range The upper limit of generated output * @return WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE on failure */ int wolfSSL_BN_rand_range(WOLFSSL_BIGNUM *r, const WOLFSSL_BIGNUM *range) { int n; int iter = 0; WOLFSSL_MSG("wolfSSL_BN_rand_range"); if (r == NULL || range == NULL) { WOLFSSL_MSG("Bad parameter"); return WOLFSSL_FAILURE; } n = wolfSSL_BN_num_bits(range); if (n <= 1) { wolfSSL_BN_zero(r); } else { do { if (iter >= 100) { WOLFSSL_MSG("wolfSSL_BN_rand_range too many iterations"); return WOLFSSL_FAILURE; } iter++; if (wolfSSL_BN_pseudo_rand(r, n, -1, 0) == WOLFSSL_FAILURE) { WOLFSSL_MSG("wolfSSL_BN_rand error"); return WOLFSSL_FAILURE; } } while(wolfSSL_BN_cmp(r, range) >= 0); } return WOLFSSL_SUCCESS; } /* WOLFSSL_SUCCESS on ok * code is same as wolfSSL_BN_rand except for how top and bottom is handled. * top -1 then leave most sig bit alone * top 0 then most sig is set to 1 * top is 1 then first two most sig bits are 1 * * bottom is hot then odd number */ int wolfSSL_BN_pseudo_rand(WOLFSSL_BIGNUM* bn, int bits, int top, int bottom) { int ret = 0; int len; int initTmpRng = 0; WC_RNG* rng = NULL; #ifdef WOLFSSL_SMALL_STACK WC_RNG* tmpRNG = NULL; byte* buff = NULL; #else WC_RNG tmpRNG[1]; byte buff[1024]; #endif WOLFSSL_ENTER("wolfSSL_BN_pseudo_rand"); if (bits <= 0) { return WOLFSSL_FAILURE; } len = bits / 8; if (bits % 8) len++; /* has to be a length of at least 1 since we set buf[0] and buf[len-1] */ if (top == 1 || top == 0 || bottom == 1) { if (len < 1) { return WOLFSSL_FAILURE; } } #ifdef WOLFSSL_SMALL_STACK buff = (byte*)XMALLOC(1024, NULL, DYNAMIC_TYPE_TMP_BUFFER); tmpRNG = (WC_RNG*) XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_TMP_BUFFER); if (buff == NULL || tmpRNG == NULL) { XFREE(buff, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(tmpRNG, NULL, DYNAMIC_TYPE_TMP_BUFFER); return ret; } #endif if (bn == NULL || bn->internal == NULL) WOLFSSL_MSG("Bad function arguments"); else if (wc_InitRng(tmpRNG) == 0) { rng = tmpRNG; initTmpRng = 1; } else if (initGlobalRNG) rng = &globalRNG; if (rng) { if (wc_RNG_GenerateBlock(rng, buff, len) != 0) WOLFSSL_MSG("Bad wc_RNG_GenerateBlock"); else { switch (top) { case -1: break; case 0: buff[0] |= 0x80; break; case 1: buff[0] |= 0x80 | 0x40; break; } if (bottom == 1) { buff[len-1] |= 0x01; } if (mp_read_unsigned_bin((mp_int*)bn->internal,buff,len) != MP_OKAY) WOLFSSL_MSG("mp read bin failed"); else ret = WOLFSSL_SUCCESS; } } if (initTmpRng) wc_FreeRng(tmpRNG); #ifdef WOLFSSL_SMALL_STACK XFREE(buff, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(tmpRNG, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return ret; } /* return code compliant with OpenSSL : * 1 if bit set, 0 else */ int wolfSSL_BN_is_bit_set(const WOLFSSL_BIGNUM* bn, int n) { if (bn == NULL || bn->internal == NULL) { WOLFSSL_MSG("bn NULL error"); return WOLFSSL_FAILURE; } return mp_is_bit_set((mp_int*)bn->internal, (mp_digit)n); } /* return code compliant with OpenSSL : * 1 if success, 0 else */ int wolfSSL_BN_set_bit(WOLFSSL_BIGNUM* bn, int n) { if (bn == NULL || bn->internal == NULL) { WOLFSSL_MSG("bn NULL error"); return WOLFSSL_FAILURE; } if (mp_set_bit((mp_int*)bn->internal, n) != MP_OKAY) { WOLFSSL_MSG("mp_set_bit error"); return WOLFSSL_FAILURE; } return WOLFSSL_SUCCESS; } int wolfSSL_BN_clear_bit(WOLFSSL_BIGNUM* bn, int n) { int ret = WOLFSSL_FAILURE; #ifndef WOLFSSL_SMALL_STACK mp_int tmp[1]; #else mp_int* tmp = NULL; #endif if (bn == NULL || bn->internal == NULL) { WOLFSSL_MSG("bn NULL error"); goto end; } if (mp_is_bit_set((mp_int*)bn->internal, n)) { #ifdef WOLFSSL_SMALL_STACK tmp = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_BIGINT); if (tmp == NULL) { goto end; } #endif if (mp_init(tmp) != MP_OKAY) { goto end; } if (mp_set_bit(tmp, n) != MP_OKAY) { goto cleanup; } if (mp_sub((mp_int*)bn->internal, tmp, (mp_int*)bn->internal) != MP_OKAY) { goto cleanup; } } else { goto end; } ret = WOLFSSL_SUCCESS; cleanup: mp_clear(tmp); end: #ifdef WOLFSSL_SMALL_STACK if (tmp) XFREE(tmp, NULL, DYNAMIC_TYPE_BIGINT); #endif return ret; } /* WOLFSSL_SUCCESS on ok */ /* Note on use: this function expects str to be an even length. It is * converting pairs of bytes into 8-bit values. As an example, the RSA * public exponent is commonly 0x010001. To get it to convert, you need * to pass in the string "010001", it will fail if you use "10001". This * is an affect of how Base16_Decode() works. */ int wolfSSL_BN_hex2bn(WOLFSSL_BIGNUM** bn, const char* str) { int ret = 0; word32 decSz = 1024; #ifdef WOLFSSL_SMALL_STACK byte* decoded; #else byte decoded[1024]; #endif int weOwn = 0; int strLen; WOLFSSL_MSG("wolfSSL_BN_hex2bn"); #ifdef WOLFSSL_SMALL_STACK decoded = (byte*)XMALLOC(decSz, NULL, DYNAMIC_TYPE_DER); if (decoded == NULL) return ret; #endif if (str == NULL || str[0] == '\0') { WOLFSSL_MSG("Bad function argument"); ret = WOLFSSL_FAILURE; } else { strLen = (int)XSTRLEN(str); /* ignore trailing new lines */ while (str[strLen-1] == '\n' && strLen > 0) strLen--; if (Base16_Decode((byte*)str, strLen, decoded, &decSz) < 0) WOLFSSL_MSG("Bad Base16_Decode error"); else if (bn == NULL) ret = decSz; else { if (*bn == NULL) { *bn = wolfSSL_BN_new(); if (*bn != NULL) { weOwn = 1; } } if (*bn == NULL) WOLFSSL_MSG("BN new failed"); else if (wolfSSL_BN_bin2bn(decoded, decSz, *bn) == NULL) { WOLFSSL_MSG("Bad bin2bn error"); if (weOwn == 1) { wolfSSL_BN_free(*bn); /* Free new BN */ } } else ret = WOLFSSL_SUCCESS; } } #ifdef WOLFSSL_SMALL_STACK XFREE(decoded, NULL, DYNAMIC_TYPE_DER); #endif return ret; } WOLFSSL_BIGNUM* wolfSSL_BN_dup(const WOLFSSL_BIGNUM* bn) { WOLFSSL_BIGNUM* ret; WOLFSSL_MSG("wolfSSL_BN_dup"); if (bn == NULL || bn->internal == NULL) { WOLFSSL_MSG("bn NULL error"); return NULL; } ret = wolfSSL_BN_new(); if (ret == NULL) { WOLFSSL_MSG("bn new error"); return NULL; } if (mp_copy((mp_int*)bn->internal, (mp_int*)ret->internal) != MP_OKAY) { WOLFSSL_MSG("mp_copy error"); wolfSSL_BN_free(ret); return NULL; } ret->neg = bn->neg; return ret; } WOLFSSL_BIGNUM* wolfSSL_BN_copy(WOLFSSL_BIGNUM* r, const WOLFSSL_BIGNUM* bn) { WOLFSSL_MSG("wolfSSL_BN_copy"); if (r == NULL || bn == NULL) { WOLFSSL_MSG("r or bn NULL error"); return NULL; } if (mp_copy((mp_int*)bn->internal, (mp_int*)r->internal) != MP_OKAY) { WOLFSSL_MSG("mp_copy error"); return NULL; } r->neg = bn->neg; return r; } /* return code compliant with OpenSSL : * 1 if success, 0 else */ int wolfSSL_BN_set_word(WOLFSSL_BIGNUM* bn, unsigned long w) { WOLFSSL_MSG("wolfSSL_BN_set_word"); if (bn == NULL) { WOLFSSL_MSG("bn NULL error"); return WOLFSSL_FAILURE; } if (mp_set_int((mp_int*)bn->internal, w) != MP_OKAY) { WOLFSSL_MSG("mp_init_set_int error"); return WOLFSSL_FAILURE; } return WOLFSSL_SUCCESS; } static WOLFSSL_BN_ULONG wolfSSL_BN_get_word_1(mp_int *mp) { #if DIGIT_BIT >= (SIZEOF_LONG * CHAR_BIT) return (WOLFSSL_BN_ULONG)mp->dp[0]; #else WOLFSSL_BN_ULONG ret = 0UL; int digit_i; for (digit_i = 0; digit_i < mp->used; ++digit_i) ret |= ((WOLFSSL_BN_ULONG)mp->dp[digit_i]) << (DIGIT_BIT * digit_i); return ret; #endif } /* Returns the big number as an unsigned long if possible. * * bn big number structure to get value from * * Returns value or 0xFFFFFFFFL if bigger than unsigned long. */ WOLFSSL_BN_ULONG wolfSSL_BN_get_word(const WOLFSSL_BIGNUM* bn) { WOLFSSL_MSG("wolfSSL_BN_get_word"); if (bn == NULL) { WOLFSSL_MSG("Invalid argument"); return 0; } if (wolfSSL_BN_num_bytes(bn) > (int)sizeof(unsigned long)) { WOLFSSL_MSG("bignum is larger than unsigned long"); return 0xFFFFFFFFL; } return wolfSSL_BN_get_word_1((mp_int*)bn->internal); } /* return code compliant with OpenSSL : * number length in decimal if success, 0 if error */ #ifndef NO_WOLFSSL_STUB int wolfSSL_BN_dec2bn(WOLFSSL_BIGNUM** bn, const char* str) { (void)bn; (void)str; WOLFSSL_MSG("wolfSSL_BN_dec2bn"); WOLFSSL_STUB("BN_dec2bn"); return SSL_FAILURE; } #endif #if defined(WOLFSSL_KEY_GEN) || defined(HAVE_COMP_KEY) char *wolfSSL_BN_bn2dec(const WOLFSSL_BIGNUM *bn) { int len = 0; char *buf; WOLFSSL_MSG("wolfSSL_BN_bn2dec"); if (bn == NULL || bn->internal == NULL) { WOLFSSL_MSG("bn NULL error"); return NULL; } if (mp_radix_size((mp_int*)bn->internal, MP_RADIX_DEC, &len) != MP_OKAY) { WOLFSSL_MSG("mp_radix_size failure"); return NULL; } buf = (char*) XMALLOC(len, NULL, DYNAMIC_TYPE_OPENSSL); if (buf == NULL) { WOLFSSL_MSG("BN_bn2dec malloc buffer failure"); return NULL; } if (mp_todecimal((mp_int*)bn->internal, buf) != MP_OKAY) { XFREE(buf, NULL, DYNAMIC_TYPE_OPENSSL); return NULL; } return buf; } #else char* wolfSSL_BN_bn2dec(const WOLFSSL_BIGNUM* bn) { (void)bn; WOLFSSL_MSG("wolfSSL_BN_bn2dec"); return NULL; } #endif /* defined(WOLFSSL_KEY_GEN) || defined(HAVE_COMP_KEY) */ /* Internal function for adding/subtracting an unsigned long from a * WOLFSSL_BIGNUM. To add, pass "sub" as 0. To subtract, pass it as 1. * Returns 1 (WOLFSSL_SUCCESS) on success and 0 (WOLFSSL_FAILURE) on failure. */ static int wolfSSL_BN_add_word_int(WOLFSSL_BIGNUM *bn, WOLFSSL_BN_ULONG w, int sub) { int ret = WOLFSSL_SUCCESS; int rc = 0; mp_int w_mp; XMEMSET(&w_mp, 0, sizeof(mp_int)); if (bn == NULL || bn->internal == NULL) { WOLFSSL_MSG("bn NULL error"); ret = WOLFSSL_FAILURE; } if (ret == WOLFSSL_SUCCESS) { if (w <= (WOLFSSL_BN_ULONG)MP_MASK) { if (sub == 1) { rc = mp_sub_d((mp_int*)bn->internal, (mp_digit)w, (mp_int*)bn->internal); } else { rc = mp_add_d((mp_int*)bn->internal, (mp_digit)w, (mp_int*)bn->internal); } if (rc != MP_OKAY) { WOLFSSL_MSG("mp_add/sub_d error"); ret = WOLFSSL_FAILURE; } } else { if (mp_init(&w_mp) != MP_OKAY) { ret = WOLFSSL_FAILURE; } if (ret == WOLFSSL_SUCCESS) { if (mp_set_int(&w_mp, w) != MP_OKAY) { ret = WOLFSSL_FAILURE; } } if (ret == WOLFSSL_SUCCESS) { if (sub == 1) { rc = mp_sub((mp_int *)bn->internal, &w_mp, (mp_int *)bn->internal); } else { rc = mp_add((mp_int *)bn->internal, &w_mp, (mp_int *)bn->internal); } if (rc != MP_OKAY) { WOLFSSL_MSG("mp_add/sub error"); ret = WOLFSSL_FAILURE; } } } } mp_free(&w_mp); return ret; } /* return code compliant with OpenSSL : * 1 if success, 0 else */ int wolfSSL_BN_add_word(WOLFSSL_BIGNUM *bn, WOLFSSL_BN_ULONG w) { int ret; WOLFSSL_ENTER("wolfSSL_BN_add_word"); ret = wolfSSL_BN_add_word_int(bn, w, 0); WOLFSSL_LEAVE("wolfSSL_BN_add_word", ret); return ret; } /* return code compliant with OpenSSL : * 1 if success, 0 else */ WOLFSSL_API int wolfSSL_BN_sub_word(WOLFSSL_BIGNUM* bn, WOLFSSL_BN_ULONG w) { int ret; WOLFSSL_ENTER("wolfSSL_BN_sub_word"); ret = wolfSSL_BN_add_word_int(bn, w, 1); WOLFSSL_LEAVE("wolfSSL_BN_sub_word", ret); return ret; } #ifndef WOLFSSL_SP_MATH /* return code compliant with OpenSSL : * 1 if success, 0 else */ int wolfSSL_BN_lshift(WOLFSSL_BIGNUM *r, const WOLFSSL_BIGNUM *bn, int n) { WOLFSSL_MSG("wolfSSL_BN_lshift"); if (r == NULL || r->internal == NULL || bn == NULL || bn->internal == NULL){ WOLFSSL_MSG("bn NULL error"); return WOLFSSL_FAILURE; } if (mp_mul_2d((mp_int*)bn->internal, n, (mp_int*)r->internal) != MP_OKAY) { WOLFSSL_MSG("mp_mul_2d error"); return WOLFSSL_FAILURE; } return WOLFSSL_SUCCESS; } /* return code compliant with OpenSSL : * 1 if success, 0 else */ int wolfSSL_BN_rshift(WOLFSSL_BIGNUM *r, const WOLFSSL_BIGNUM *bn, int n) { WOLFSSL_MSG("wolfSSL_BN_rshift"); if (r == NULL || r->internal == NULL || bn == NULL || bn->internal == NULL){ WOLFSSL_MSG("bn NULL error"); return WOLFSSL_FAILURE; } if (mp_div_2d((mp_int*)bn->internal, n, (mp_int*)r->internal, NULL) != MP_OKAY) { WOLFSSL_MSG("mp_mul_2d error"); return WOLFSSL_FAILURE; } return WOLFSSL_SUCCESS; } #endif /* return code compliant with OpenSSL : * 1 if success, 0 else */ int wolfSSL_BN_add(WOLFSSL_BIGNUM *r, WOLFSSL_BIGNUM *a, WOLFSSL_BIGNUM *b) { WOLFSSL_MSG("wolfSSL_BN_add"); if (r == NULL || r->internal == NULL || a == NULL || a->internal == NULL || b == NULL || b->internal == NULL) { WOLFSSL_MSG("bn NULL error"); return WOLFSSL_FAILURE; } if (mp_add((mp_int*)a->internal, (mp_int*)b->internal, (mp_int*)r->internal) != MP_OKAY) { WOLFSSL_MSG("mp_add_d error"); return WOLFSSL_FAILURE; } return WOLFSSL_SUCCESS; } #ifndef WOLFSSL_SP_MATH /* r = a + b (mod m) */ int wolfSSL_BN_mod_add(WOLFSSL_BIGNUM *r, const WOLFSSL_BIGNUM *a, const WOLFSSL_BIGNUM *b, const WOLFSSL_BIGNUM *m, WOLFSSL_BN_CTX *ctx) { (void)ctx; WOLFSSL_MSG("wolfSSL_BN_add"); if (r == NULL || r->internal == NULL || a == NULL || a->internal == NULL || b == NULL || b->internal == NULL || m == NULL || m->internal == NULL) { WOLFSSL_MSG("bn NULL error"); return WOLFSSL_FAILURE; } if (mp_addmod((mp_int*)a->internal, (mp_int*)b->internal, (mp_int*)m->internal, (mp_int*)r->internal) != MP_OKAY) { WOLFSSL_MSG("mp_add_d error"); return WOLFSSL_FAILURE; } return WOLFSSL_SUCCESS; } #endif #if defined(WOLFSSL_KEY_GEN) && (!defined(NO_RSA) || !defined(NO_DH) || !defined(NO_DSA)) int wolfSSL_BN_generate_prime_ex(WOLFSSL_BIGNUM* prime, int bits, int safe, const WOLFSSL_BIGNUM* add, const WOLFSSL_BIGNUM* rem, WOLFSSL_BN_GENCB* cb) { int ret = WOLFSSL_SUCCESS; #ifdef WOLFSSL_SMALL_STACK WC_RNG* rng = NULL; #else WC_RNG rng[1]; #endif (void)cb; WOLFSSL_ENTER("wolfSSL_BN_generate_prime_ex"); if (safe == 1 || add != NULL || rem != NULL) { /* These parameters aren't supported, yet. */ ret = WOLFSSL_FAILURE; } if (prime == NULL || prime->internal == NULL) { ret = WOLFSSL_FAILURE; } #ifdef WOLFSSL_SMALL_STACK if (ret == WOLFSSL_SUCCESS) { rng = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG); if (rng == NULL) { ret = WOLFSSL_FAILURE; } } #endif if (ret == WOLFSSL_SUCCESS) { XMEMSET(rng, 0, sizeof(WC_RNG)); if (wc_InitRng(rng) != 0) { ret = WOLFSSL_FAILURE; } } if (ret == WOLFSSL_SUCCESS) { if (mp_rand_prime((mp_int*)prime->internal, (bits + 7) / 8, rng, NULL) != MP_OKAY) { ret = WOLFSSL_FAILURE; } } wc_FreeRng(rng); #ifdef WOLFSSL_SMALL_STACK if (rng != NULL) XFREE(rng, NULL, DYNAMIC_TYPE_RNG); #endif WOLFSSL_LEAVE("wolfSSL_BN_generate_prime_ex", ret); return ret; } /* return code compliant with OpenSSL : * 1 if prime, 0 if not, -1 if error */ int wolfSSL_BN_is_prime_ex(const WOLFSSL_BIGNUM *bn, int nbchecks, WOLFSSL_BN_CTX *ctx, WOLFSSL_BN_GENCB *cb) { WC_RNG* rng = NULL; #ifdef WOLFSSL_SMALL_STACK WC_RNG* tmpRNG = NULL; #else WC_RNG tmpRNG[1]; #endif int initTmpRng = 0; int res = MP_NO; (void)ctx; (void)cb; WOLFSSL_MSG("wolfSSL_BN_is_prime_ex"); if (bn == NULL || bn->internal == NULL) { WOLFSSL_MSG("bn NULL error"); return WOLFSSL_FATAL_ERROR; } #ifdef WOLFSSL_SMALL_STACK tmpRNG = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG); if (tmpRNG == NULL) return WOLFSSL_FAILURE; #endif if (wc_InitRng(tmpRNG) == 0) { rng = tmpRNG; initTmpRng = 1; } else { WOLFSSL_MSG("Bad RNG Init, trying global"); if (initGlobalRNG == 0) { WOLFSSL_MSG("Global RNG no Init"); } else rng = &globalRNG; } if (rng) { if (mp_prime_is_prime_ex((mp_int*)bn->internal, nbchecks, &res, rng) != MP_OKAY) { WOLFSSL_MSG("mp_prime_is_prime_ex error"); res = MP_NO; } } if (initTmpRng) wc_FreeRng(tmpRNG); #ifdef WOLFSSL_SMALL_STACK XFREE(tmpRNG, NULL, DYNAMIC_TYPE_RNG); #endif if (res != MP_YES) { WOLFSSL_MSG("mp_prime_is_prime_ex not prime"); return WOLFSSL_FAILURE; } return WOLFSSL_SUCCESS; } /* return code compliant with OpenSSL : * (bn mod w) if success, -1 if error */ WOLFSSL_BN_ULONG wolfSSL_BN_mod_word(const WOLFSSL_BIGNUM *bn, WOLFSSL_BN_ULONG w) { WOLFSSL_BN_ULONG ret = 0; WOLFSSL_MSG("wolfSSL_BN_mod_word"); if (bn == NULL || bn->internal == NULL) { WOLFSSL_MSG("bn NULL error"); return (WOLFSSL_BN_ULONG)WOLFSSL_FATAL_ERROR; } if (w <= (WOLFSSL_BN_ULONG)MP_MASK) { mp_digit bn_ret; if (mp_mod_d((mp_int*)bn->internal, (mp_digit)w, &bn_ret) != MP_OKAY) { WOLFSSL_MSG("mp_add_d error"); return (WOLFSSL_BN_ULONG)WOLFSSL_FATAL_ERROR; } ret = (WOLFSSL_BN_ULONG)bn_ret; } else { int mp_ret; mp_int w_mp, r_mp; if (mp_init(&w_mp) != MP_OKAY) return (unsigned long)WOLFSSL_FAILURE; if (mp_init(&r_mp) != MP_OKAY) return (unsigned long)WOLFSSL_FAILURE; if (mp_set_int(&w_mp, w) != MP_OKAY) return (unsigned long)WOLFSSL_FAILURE; mp_ret = mp_mod((mp_int *)bn->internal, &w_mp, &r_mp); ret = wolfSSL_BN_get_word_1(&r_mp); mp_free(&r_mp); mp_free(&w_mp); if (mp_ret != MP_OKAY) { WOLFSSL_MSG("mp_mod error"); return (WOLFSSL_BN_ULONG)WOLFSSL_FAILURE; } } return ret; } #endif /* WOLFSSL_KEY_GEN && (!NO_RSA || !NO_DH || !NO_DSA) */ char *wolfSSL_BN_bn2hex(const WOLFSSL_BIGNUM *bn) { int len = 0; char *buf; WOLFSSL_ENTER("wolfSSL_BN_bn2hex"); if (bn == NULL || bn->internal == NULL) { WOLFSSL_MSG("bn NULL error"); return NULL; } if (mp_radix_size((mp_int*)bn->internal, MP_RADIX_HEX, &len) != MP_OKAY) { WOLFSSL_MSG("mp_radix_size failure"); return NULL; } buf = (char*)XMALLOC(len, NULL, DYNAMIC_TYPE_OPENSSL); if (buf == NULL) { WOLFSSL_MSG("BN_bn2hex malloc buffer failure"); return NULL; } if (mp_tohex((mp_int*)bn->internal, buf) != MP_OKAY) { XFREE(buf, NULL, DYNAMIC_TYPE_OPENSSL); return NULL; } return buf; } #ifndef NO_FILESYSTEM /* return code compliant with OpenSSL : * 1 if success, 0 if error */ int wolfSSL_BN_print_fp(XFILE fp, const WOLFSSL_BIGNUM *bn) { char *buf; WOLFSSL_ENTER("wolfSSL_BN_print_fp"); if (fp == XBADFILE || bn == NULL || bn->internal == NULL) { WOLFSSL_MSG("bn NULL error"); return WOLFSSL_FAILURE; } buf = wolfSSL_BN_bn2hex(bn); if (buf == NULL) { WOLFSSL_MSG("wolfSSL_BN_bn2hex failure"); return WOLFSSL_FAILURE; } XFPRINTF(fp, "%s", buf); XFREE(buf, NULL, DYNAMIC_TYPE_OPENSSL); return WOLFSSL_SUCCESS; } #endif /* !NO_FILESYSTEM */ WOLFSSL_BIGNUM *wolfSSL_BN_CTX_get(WOLFSSL_BN_CTX *ctx) { /* ctx is not used, return new Bignum */ (void)ctx; WOLFSSL_ENTER("wolfSSL_BN_CTX_get"); return wolfSSL_BN_new(); } #ifndef NO_WOLFSSL_STUB void wolfSSL_BN_CTX_start(WOLFSSL_BN_CTX *ctx) { (void)ctx; WOLFSSL_ENTER("wolfSSL_BN_CTX_start"); WOLFSSL_STUB("BN_CTX_start"); WOLFSSL_MSG("wolfSSL_BN_CTX_start TBD"); } #endif WOLFSSL_BIGNUM *wolfSSL_BN_mod_inverse(WOLFSSL_BIGNUM *r, WOLFSSL_BIGNUM *a, const WOLFSSL_BIGNUM *n, WOLFSSL_BN_CTX *ctx) { int dynamic = 0; /* ctx is not used */ (void)ctx; WOLFSSL_ENTER("wolfSSL_BN_mod_inverse"); /* check parameter */ if (r == NULL) { r = wolfSSL_BN_new(); if (r == NULL){ WOLFSSL_MSG("WolfSSL_BN_new() failed"); return NULL; } dynamic = 1; } if (a == NULL) { WOLFSSL_MSG("a NULL error"); if (dynamic == 1) { wolfSSL_BN_free(r); } return NULL; } if (n == NULL) { WOLFSSL_MSG("n NULL error"); if (dynamic == 1) { wolfSSL_BN_free(r); } return NULL; } /* Compute inverse of a modulo n and return r */ if (mp_invmod((mp_int *)a->internal,(mp_int *)n->internal, (mp_int*)r->internal) == MP_VAL){ WOLFSSL_MSG("mp_invmod() error"); if (dynamic == 1) { wolfSSL_BN_free(r); } return NULL; } return r; } #endif /* OPENSSL_EXTRA */ #if (defined(WOLFSSL_QT) || defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA)) && \ !defined(NO_ASN) #ifndef NO_BIO static int unprintable_char(char c) { const unsigned char last_unprintable = 31; const unsigned char LF = 10; const unsigned char CR = 13; if (c <= last_unprintable && c != LF && c != CR) { return 1; } return 0; } int wolfSSL_ASN1_STRING_print(WOLFSSL_BIO *out, WOLFSSL_ASN1_STRING *str) { int i; WOLFSSL_ENTER("wolfSSL_ASN1_STRING_print"); if (out == NULL || str == NULL) return WOLFSSL_FAILURE; for (i=0; i < str->length; i++) { if (unprintable_char(str->data[i])) { str->data[i] = '.'; } } if (wolfSSL_BIO_write(out, str->data, str->length) != str->length){ return WOLFSSL_FAILURE; } return str->length; } #endif /* !NO_BIO */ #endif /* (WOLFSSL_QT || OPENSSL_ALL || OPENSSL_EXTRA) && !NO_ASN */ #if defined(OPENSSL_EXTRA) const char *wolfSSL_ASN1_tag2str(int tag) { static const char *const tag_label[31] = { "EOC", "BOOLEAN", "INTEGER", "BIT STRING", "OCTET STRING", "NULL", "OBJECT", "OBJECT DESCRIPTOR", "EXTERNAL", "REAL", "ENUMERATED", "", "UTF8STRING", "", "", "", "SEQUENCE", "SET", "NUMERICSTRING", "PRINTABLESTRING", "T61STRING", "VIDEOTEXTSTRING", "IA5STRING", "UTCTIME", "GENERALIZEDTIME", "GRAPHICSTRING", "VISIBLESTRING", "GENERALSTRING", "UNIVERSALSTRING", "", "BMPSTRING" }; if ((tag == V_ASN1_NEG_INTEGER) || (tag == V_ASN1_NEG_ENUMERATED)) tag &= ~0x100; if (tag < 0 || tag > 30) return "(unknown)"; return tag_label[tag]; } #ifndef NO_BIO static int check_esc_char(char c, char *esc) { char *ptr; ptr = esc; while(*ptr != 0){ if (c == *ptr) return 1; ptr++; } return 0; } int wolfSSL_ASN1_STRING_print_ex(WOLFSSL_BIO *out, WOLFSSL_ASN1_STRING *str, unsigned long flags) { size_t str_len = 0, type_len = 0; unsigned char *typebuf = NULL; const char *hash="#"; WOLFSSL_ENTER("wolfSSL_ASN1_STRING_PRINT_ex"); if (out == NULL || str == NULL) return WOLFSSL_FAILURE; /* add ASN1 type tag */ if (flags & ASN1_STRFLGS_SHOW_TYPE){ const char *tag = wolfSSL_ASN1_tag2str(str->type); /* colon len + tag len + null*/ type_len = XSTRLEN(tag) + 2; typebuf = (unsigned char *)XMALLOC(type_len , NULL, DYNAMIC_TYPE_TMP_BUFFER); if (typebuf == NULL){ WOLFSSL_MSG("memory alloc failed."); return WOLFSSL_FAILURE; } XMEMSET(typebuf, 0, type_len); XSNPRINTF((char*)typebuf, (size_t)type_len , "%s:", tag); type_len--; } /* dump hex */ if (flags & ASN1_STRFLGS_DUMP_ALL){ char hex_tmp[4]; char *str_ptr, *str_end; if (type_len > 0){ if (wolfSSL_BIO_write(out, typebuf, (int)type_len) != (int)type_len){ XFREE(typebuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); return WOLFSSL_FAILURE; } str_len += type_len; } if (wolfSSL_BIO_write(out, hash, 1) != 1){ goto err_exit; } str_len++; if (flags & ASN1_STRFLGS_DUMP_DER){ ByteToHexStr((byte)str->type, &hex_tmp[0]); ByteToHexStr((byte)str->length, &hex_tmp[2]); if (wolfSSL_BIO_write(out, hex_tmp, 4) != 4){ goto err_exit; } str_len += 4; XMEMSET(hex_tmp, 0, 4); } str_ptr = str->data; str_end = str->data + str->length; while (str_ptr < str_end){ ByteToHexStr((byte)*str_ptr, &hex_tmp[0]); if (wolfSSL_BIO_write(out, hex_tmp, 2) != 2){ goto err_exit; } str_ptr++; str_len += 2; } if (type_len > 0) XFREE(typebuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); return (int)str_len; } if (type_len > 0){ if (wolfSSL_BIO_write(out, typebuf, (int)type_len) != (int)type_len){ XFREE(typebuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); return WOLFSSL_FAILURE; } str_len += type_len; } if (flags & ASN1_STRFLGS_ESC_2253){ char esc_ch[] = "+;<>\\"; char* esc_ptr; esc_ptr = str->data; while (*esc_ptr != 0){ if (check_esc_char(*esc_ptr, esc_ch)){ if (wolfSSL_BIO_write(out,"\\", 1) != 1) goto err_exit; str_len++; } if (wolfSSL_BIO_write(out, esc_ptr, 1) != 1) goto err_exit; str_len++; esc_ptr++; } if (type_len > 0) XFREE(typebuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); return (int)str_len; } if (wolfSSL_BIO_write(out, str->data, str->length) != str->length){ goto err_exit; } str_len += str->length; if (type_len > 0) XFREE(typebuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); return (int)str_len; err_exit: if (type_len > 0) XFREE(typebuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); return WOLFSSL_FAILURE; } #endif /* !NO_BIO */ #if !defined(NO_ASN_TIME) && !defined(USER_TIME) && !defined(TIME_OVERRIDES) WOLFSSL_ASN1_TIME* wolfSSL_ASN1_TIME_adj(WOLFSSL_ASN1_TIME *s, time_t t, int offset_day, long offset_sec) { const time_t sec_per_day = 24*60*60; time_t t_adj = 0; time_t offset_day_sec = 0; char time_str[MAX_TIME_STRING_SZ]; int time_get; WOLFSSL_ENTER("wolfSSL_ASN1_TIME_adj"); if (s == NULL) { s = wolfSSL_ASN1_TIME_new(); if (s == NULL) { return NULL; } } /* compute GMT time with offset */ offset_day_sec = offset_day * sec_per_day; t_adj = t + offset_day_sec + offset_sec; /* Get time string as either UTC or GeneralizedTime */ time_get = GetFormattedTime(&t_adj, (byte*)time_str, (word32)sizeof(time_str)); if (time_get <= 0) { wolfSSL_ASN1_TIME_free(s); return NULL; } if (wolfSSL_ASN1_TIME_set_string(s, time_str) != WOLFSSL_SUCCESS) { wolfSSL_ASN1_TIME_free(s); return NULL; } return s; } #endif /* !NO_ASN_TIME && !USER_TIME && !TIME_OVERRIDES */ #ifndef NO_ASN_TIME WOLFSSL_ASN1_TIME* wolfSSL_ASN1_TIME_new(void) { WOLFSSL_ASN1_TIME* ret = (WOLFSSL_ASN1_TIME*) XMALLOC(sizeof(WOLFSSL_ASN1_TIME), NULL, DYNAMIC_TYPE_OPENSSL); if (!ret) return NULL; XMEMSET(ret, 0, sizeof(WOLFSSL_ASN1_TIME)); return ret; } void wolfSSL_ASN1_TIME_free(WOLFSSL_ASN1_TIME* t) { if (t) { XFREE(t, NULL, DYNAMIC_TYPE_OPENSSL); } } /* not a compatibility function - length getter for opaque type */ int wolfSSL_ASN1_TIME_get_length(WOLFSSL_ASN1_TIME *t) { WOLFSSL_ENTER("wolfSSL_ASN1_TIME_get_length"); if (t == NULL) return WOLFSSL_FAILURE; return t->length; } /* not a compatibility function - data getter for opaque type */ unsigned char* wolfSSL_ASN1_TIME_get_data(WOLFSSL_ASN1_TIME *t) { WOLFSSL_ENTER("wolfSSL_ASN1_TIME_get_data"); if (t == NULL) return NULL; return t->data; } WOLFSSL_ASN1_TIME* wolfSSL_ASN1_TIME_to_generalizedtime(WOLFSSL_ASN1_TIME *t, WOLFSSL_ASN1_TIME **out) { int time_type = 0; WOLFSSL_ASN1_TIME *ret = NULL; WOLFSSL_ENTER("wolfSSL_ASN1_TIME_to_generalizedtime"); if (t == NULL) { WOLFSSL_MSG("Invalid ASN_TIME value"); } else { time_type = t->type; if (time_type != ASN_UTC_TIME && time_type != ASN_GENERALIZED_TIME){ WOLFSSL_MSG("Invalid ASN_TIME type."); } else { if (out == NULL || *out == NULL) { ret = wolfSSL_ASN1_TIME_new(); if (ret == NULL){ WOLFSSL_MSG("memory alloc failed."); } } else { ret = *out; } } } if (ret != NULL) { if (time_type == ASN_GENERALIZED_TIME){ XMEMCPY(ret->data, t->data, ASN_GENERALIZED_TIME_SIZE); } else { /* ASN_UTC_TIME */ /* convert UTC to generalized time */ ret->type = ASN_GENERALIZED_TIME; ret->length = ASN_GENERALIZED_TIME_SIZE; if (t->data[0] >= '5') { ret->data[0] = '1'; ret->data[1] = '9'; } else { ret->data[0] = '2'; ret->data[1] = '0'; } XMEMCPY(&ret->data[2], t->data, ASN_UTC_TIME_SIZE); } } return ret; } #endif /* !NO_ASN_TIME */ #ifndef NO_ASN int wolfSSL_i2c_ASN1_INTEGER(WOLFSSL_ASN1_INTEGER *a, unsigned char **pp) { unsigned char *pptr = NULL; char pad = 0 ; unsigned char pad_val = 0; int ret_size = 0; unsigned char data1 = 0; unsigned char neg = 0; int i = 0; WOLFSSL_ENTER("wolfSSL_i2c_ASN1_INTEGER"); if (a == NULL) return WOLFSSL_FAILURE; ret_size = a->intData[1]; if (ret_size == 0) ret_size = 1; else{ ret_size = (int)a->intData[1]; neg = a->negative; data1 = a->intData[2]; if (ret_size == 1 && data1 == 0) neg = 0; /* 0x80 or greater positive number in first byte */ if (!neg && (data1 > 127)){ pad = 1; pad_val = 0; } else if (neg){ /* negative number */ if (data1 > 128){ pad = 1; pad_val = 0xff; } else if (data1 == 128){ for (i = 3; i < a->intData[1] + 2; i++){ if (a->intData[i]){ pad = 1; pad_val = 0xff; break; } } } } ret_size += (int)pad; } if (pp == NULL) return ret_size; pptr = *pp; if (pad) *(pptr++) = pad_val; if (a->intData[1] == 0) *(pptr++) = 0; else if (!neg){ /* positive number */ for (i=0; i < a->intData[1]; i++){ *pptr = a->intData[i+2]; pptr++; } } else { /* negative number */ int str_len = 0; /* 0 padding from end of buffer */ str_len = (int)a->intData[1]; pptr += a->intData[1] - 1; while (!a->intData[str_len + 2] && str_len > 1){ *(pptr--) = 0; str_len--; } /* 2's complement next octet */ *(pptr--) = ((a->intData[str_len + 1]) ^ 0xff) + 1; str_len--; /* Complement any octets left */ while (str_len > 0){ *(pptr--) = a->intData[str_len + 1] ^ 0xff; str_len--; } } *pp += ret_size; return ret_size; } #endif /* !NO_ASN */ #endif /* OPENSSL_EXTRA */ #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) /* when calling SetIndividualExternal, mpi should be cleared by caller if no * longer used. ie mp_free(mpi). This is to free data when fastmath is * disabled since a copy of mpi is made by this function and placed into bn. */ int SetIndividualExternal(WOLFSSL_BIGNUM** bn, mp_int* mpi) { byte dynamic = 0; #ifdef WOLFSSL_DEBUG_OPENSSL WOLFSSL_MSG("Entering SetIndividualExternal"); #endif if (mpi == NULL || bn == NULL) { WOLFSSL_MSG("mpi NULL error"); return WOLFSSL_FATAL_ERROR; } if (*bn == NULL) { *bn = wolfSSL_BN_new(); if (*bn == NULL) { WOLFSSL_MSG("SetIndividualExternal alloc failed"); return WOLFSSL_FATAL_ERROR; } dynamic = 1; } if (mp_copy(mpi, (mp_int*)((*bn)->internal)) != MP_OKAY) { WOLFSSL_MSG("mp_copy error"); if (dynamic == 1) { wolfSSL_BN_free(*bn); } return WOLFSSL_FATAL_ERROR; } return WOLFSSL_SUCCESS; } static void InitwolfSSL_BigNum(WOLFSSL_BIGNUM* bn) { if (bn) XMEMSET(bn, 0, sizeof(WOLFSSL_BIGNUM)); } WOLFSSL_BIGNUM* wolfSSL_BN_new(void) { WOLFSSL_BIGNUM* external; mp_int* mpi; #ifdef WOLFSSL_DEBUG_OPENSSL WOLFSSL_MSG("wolfSSL_BN_new"); #endif #if !defined(USE_FAST_MATH) || defined(HAVE_WOLF_BIGINT) mpi = (mp_int*) XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_BIGINT); if (mpi == NULL) { WOLFSSL_MSG("wolfSSL_BN_new malloc mpi failure"); return NULL; } #endif external = (WOLFSSL_BIGNUM*) XMALLOC(sizeof(WOLFSSL_BIGNUM), NULL, DYNAMIC_TYPE_BIGINT); if (external == NULL) { WOLFSSL_MSG("wolfSSL_BN_new malloc WOLFSSL_BIGNUM failure"); #if !defined(USE_FAST_MATH) || defined(HAVE_WOLF_BIGINT) XFREE(mpi, NULL, DYNAMIC_TYPE_BIGINT); #endif return NULL; } #if defined(USE_FAST_MATH) && !defined(HAVE_WOLF_BIGINT) mpi = &external->fp; #endif InitwolfSSL_BigNum(external); if (mp_init(mpi) != MP_OKAY) { wolfSSL_BN_free(external); return NULL; } external->internal = mpi; return external; } #if defined(USE_FAST_MATH) && !defined(HAVE_WOLF_BIGINT) /* This function works without BN_free only with TFM */ void wolfSSL_BN_init(WOLFSSL_BIGNUM* bn) { if(bn == NULL)return; #ifdef WOLFSSL_DEBUG_OPENSSL WOLFSSL_MSG("wolfSSL_BN_init"); #endif InitwolfSSL_BigNum(bn); if (mp_init(&bn->fp) != MP_OKAY) return; bn->internal = (void *)&bn->fp; } #endif void wolfSSL_BN_free(WOLFSSL_BIGNUM* bn) { #ifdef WOLFSSL_DEBUG_OPENSSL WOLFSSL_MSG("wolfSSL_BN_free"); #endif if (bn) { if (bn->internal) { mp_int* bni = (mp_int*)bn->internal; mp_free(bni); #if !defined(USE_FAST_MATH) || defined(HAVE_WOLF_BIGINT) XFREE(bn->internal, NULL, DYNAMIC_TYPE_BIGINT); #endif bn->internal = NULL; } XFREE(bn, NULL, DYNAMIC_TYPE_BIGINT); /* bn = NULL, don't try to access or double free it */ } } void wolfSSL_BN_clear_free(WOLFSSL_BIGNUM* bn) { #ifdef WOLFSSL_DEBUG_OPENSSL WOLFSSL_MSG("wolfSSL_BN_clear_free"); #endif if (bn) { if (bn->internal) { mp_int* bni = (mp_int*)bn->internal; mp_forcezero(bni); } wolfSSL_BN_free(bn); } } void wolfSSL_BN_clear(WOLFSSL_BIGNUM* bn) { #ifdef WOLFSSL_DEBUG_OPENSSL WOLFSSL_MSG("wolfSSL_BN_clear"); #endif if (bn && bn->internal) { mp_forcezero((mp_int*)bn->internal); } } #endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ #ifdef OPENSSL_ALL #if !defined(NO_BIO) && !defined(NO_PWDBASED) && defined(HAVE_PKCS8) int wolfSSL_PEM_write_bio_PKCS8PrivateKey(WOLFSSL_BIO* bio, WOLFSSL_EVP_PKEY* pkey, const WOLFSSL_EVP_CIPHER* enc, char* passwd, int passwdSz, wc_pem_password_cb* cb, void* ctx) { int ret = 0; char password[NAME_SZ]; byte* key = NULL; word32 keySz; byte* pem = NULL; int pemSz; int type = PKCS8_PRIVATEKEY_TYPE; int algId; const byte* curveOid; word32 oidSz; int encAlgId = 0; if (bio == NULL || pkey == NULL) return -1; keySz = pkey->pkey_sz + 128; key = (byte*)XMALLOC(keySz, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (key == NULL) ret = MEMORY_E; if (ret == 0 && enc != NULL && passwd == NULL) { passwdSz = cb(password, sizeof(password), 1, ctx); if (passwdSz < 0) ret = WOLFSSL_FAILURE; passwd = password; } if (ret == 0 && enc != NULL) { WC_RNG rng; ret = wc_InitRng(&rng); if (ret == 0) { #ifndef NO_DES3 if (enc == EVP_DES_CBC) encAlgId = DESb; else if (enc == EVP_DES_EDE3_CBC) encAlgId = DES3b; else #endif #if !defined(NO_AES) && defined(HAVE_AES_CBC) #ifdef WOLFSSL_AES_256 if (enc == EVP_AES_256_CBC) encAlgId = AES256CBCb; else #endif #endif ret = -1; if (ret == 0) { ret = TraditionalEnc((byte*)pkey->pkey.ptr, pkey->pkey_sz, key, &keySz, passwd, passwdSz, PKCS5, PBES2, encAlgId, NULL, 0, WC_PKCS12_ITT_DEFAULT, &rng, NULL); if (ret > 0) { keySz = ret; ret = 0; } } wc_FreeRng(&rng); } type = PKCS8_ENC_PRIVATEKEY_TYPE; } if (ret == 0 && enc == NULL) { type = PKCS8_PRIVATEKEY_TYPE; #ifdef HAVE_ECC if (pkey->type == EVP_PKEY_EC) { algId = ECDSAk; ret = wc_ecc_get_oid(pkey->ecc->group->curve_oid, &curveOid, &oidSz); } else #endif { algId = RSAk; curveOid = NULL; oidSz = 0; } #ifdef HAVE_ECC if (ret >= 0) #endif { ret = wc_CreatePKCS8Key(key, &keySz, (byte*)pkey->pkey.ptr, pkey->pkey_sz, algId, curveOid, oidSz); keySz = ret; } } if (password == passwd) XMEMSET(password, 0, passwdSz); if (ret >= 0) { pemSz = 2 * keySz + 2 * 64; pem = (byte*)XMALLOC(pemSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (pem == NULL) ret = MEMORY_E; } if (ret >= 0) ret = wc_DerToPemEx(key, keySz, pem, pemSz, NULL, type); if (key != NULL) XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (ret >= 0) { if (wolfSSL_BIO_write(bio, pem, ret) != ret) ret = -1; } if (pem != NULL) XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER); return ret < 0 ? 0 : ret; } #if !defined(NO_FILESYSTEM) && !defined(NO_STDIO_FILESYSTEM) int wolfSSL_PEM_write_PKCS8PrivateKey(XFILE f, WOLFSSL_EVP_PKEY* pkey, const WOLFSSL_EVP_CIPHER* enc, char* passwd, int passwdSz, wc_pem_password_cb* cb, void* ctx) { int ret = WOLFSSL_SUCCESS; BIO *b; WOLFSSL_ENTER("wolfSSL_PEM_write_PKCS8PrivateKey"); b = wolfSSL_BIO_new_fp(f, BIO_NOCLOSE); if (b == NULL) { ret = WOLFSSL_FAILURE; } if (ret == WOLFSSL_SUCCESS) { ret = wolfSSL_PEM_write_bio_PKCS8PrivateKey(b, pkey, enc, passwd, passwdSz, cb, ctx); } wolfSSL_BIO_free(b); return ret; } #endif /* !NO_FILESYSTEM && !NO_STDIO_FILESYSTEM */ static int bio_get_data(WOLFSSL_BIO* bio, byte** data) { int ret = 0; byte* mem = NULL; #ifndef NO_FILESYSTEM long memSz; XFILE file; long curr; #endif if ((ret = wolfSSL_BIO_pending(bio)) > 0) { } #ifndef NO_FILESYSTEM else if (bio->type == WOLFSSL_BIO_FILE) { if (wolfSSL_BIO_get_fp(bio, &file) != WOLFSSL_SUCCESS) ret = BAD_FUNC_ARG; if (ret == 0) { curr = XFTELL(file); if (curr < 0) { ret = WOLFSSL_BAD_FILE; } if (XFSEEK(file, 0, XSEEK_END) != 0) ret = WOLFSSL_BAD_FILE; } if (ret == 0) { memSz = XFTELL(file); if (memSz > MAX_WOLFSSL_FILE_SIZE || memSz < 0) { ret = WOLFSSL_BAD_FILE; } } if (ret == 0) { memSz -= curr; ret = (int)memSz; if (XFSEEK(file, curr, SEEK_SET) != 0) ret = WOLFSSL_BAD_FILE; } } #endif if (ret > 0) { mem = (byte*)XMALLOC(ret, bio->heap, DYNAMIC_TYPE_OPENSSL); if (mem == NULL) { WOLFSSL_MSG("Memory error"); ret = MEMORY_E; } if (ret >= 0) { if ((ret = wolfSSL_BIO_read(bio, mem, ret)) <= 0) { XFREE(mem, bio->heap, DYNAMIC_TYPE_OPENSSL); ret = MEMORY_E; mem = NULL; } } } *data = mem; return ret; } /* DER data is PKCS#8 encrypted. */ WOLFSSL_EVP_PKEY* wolfSSL_d2i_PKCS8PrivateKey_bio(WOLFSSL_BIO* bio, WOLFSSL_EVP_PKEY** pkey, wc_pem_password_cb* cb, void* ctx) { int ret; byte* der; int len; byte* p; word32 algId; WOLFSSL_EVP_PKEY* key; if ((len = bio_get_data(bio, &der)) < 0) return NULL; if (cb != NULL) { char password[NAME_SZ]; int passwordSz = cb(password, sizeof(password), PEM_PASS_READ, ctx); if (passwordSz < 0) { XFREE(der, bio->heap, DYNAMIC_TYPE_OPENSSL); return NULL; } #ifdef WOLFSSL_CHECK_MEM_ZERO wc_MemZero_Add("wolfSSL_d2i_PKCS8PrivateKey_bio password", password, passwordSz); #endif ret = ToTraditionalEnc(der, len, password, passwordSz, &algId); if (ret < 0) { XFREE(der, bio->heap, DYNAMIC_TYPE_OPENSSL); return NULL; } ForceZero(password, passwordSz); #ifdef WOLFSSL_CHECK_MEM_ZERO wc_MemZero_Check(password, passwordSz); #endif } p = der; key = wolfSSL_d2i_PrivateKey_EVP(pkey, &p, len); XFREE(der, bio->heap, DYNAMIC_TYPE_OPENSSL); return key; } #endif /* !NO_BIO && !NO_PWDBASED && HAVE_PKCS8 */ /* Detect which type of key it is before decoding. */ WOLFSSL_EVP_PKEY* wolfSSL_d2i_AutoPrivateKey(WOLFSSL_EVP_PKEY** pkey, const unsigned char** pp, long length) { int ret; WOLFSSL_EVP_PKEY* key = NULL; const byte* der = *pp; word32 idx = 0; int len = 0; word32 end = 0; int cnt = 0; int type; word32 algId; word32 keyLen = (word32)length; /* Take off PKCS#8 wrapper if found. */ if ((len = ToTraditionalInline_ex(der, &idx, keyLen, &algId)) >= 0) { der += idx; keyLen = len; } idx = 0; len = 0; /* Use the number of elements in the outer sequence to determine key type. */ ret = GetSequence(der, &idx, &len, keyLen); if (ret >= 0) { end = idx + len; while (ret >= 0 && idx < end) { /* Skip type */ idx++; /* Get length and skip over - keeping count */ len = 0; ret = GetLength(der, &idx, &len, keyLen); if (ret >= 0) { if (idx + len > end) ret = ASN_PARSE_E; else { idx += len; cnt++; } } } } if (ret >= 0) { /* ECC includes version, private[, curve][, public key] */ if (cnt >= 2 && cnt <= 4) type = EVP_PKEY_EC; else type = EVP_PKEY_RSA; key = wolfSSL_d2i_PrivateKey(type, pkey, &der, keyLen); *pp = der; } return key; } #endif /* OPENSSL_ALL */ #ifdef WOLFSSL_STATIC_EPHEMERAL int wolfSSL_StaticEphemeralKeyLoad(WOLFSSL* ssl, int keyAlgo, void* keyPtr) { int ret; word32 idx = 0; DerBuffer* der = NULL; if (ssl == NULL || ssl->ctx == NULL || keyPtr == NULL) { return BAD_FUNC_ARG; } #ifndef SINGLE_THREADED if (!ssl->ctx->staticKELockInit) { return BUFFER_E; /* no keys set */ } ret = wc_LockMutex(&ssl->ctx->staticKELock); if (ret != 0) { return ret; } #endif ret = BUFFER_E; /* set default error */ switch (keyAlgo) { #ifndef NO_DH case WC_PK_TYPE_DH: if (ssl != NULL) der = ssl->staticKE.dhKey; if (der == NULL) der = ssl->ctx->staticKE.dhKey; if (der != NULL) { DhKey* key = (DhKey*)keyPtr; WOLFSSL_MSG("Using static DH key"); ret = wc_DhKeyDecode(der->buffer, &idx, key, der->length); } break; #endif #ifdef HAVE_ECC case WC_PK_TYPE_ECDH: if (ssl != NULL) der = ssl->staticKE.ecKey; if (der == NULL) der = ssl->ctx->staticKE.ecKey; if (der != NULL) { ecc_key* key = (ecc_key*)keyPtr; WOLFSSL_MSG("Using static ECDH key"); ret = wc_EccPrivateKeyDecode(der->buffer, &idx, key, der->length); } break; #endif #ifdef HAVE_CURVE25519 case WC_PK_TYPE_CURVE25519: if (ssl != NULL) der = ssl->staticKE.x25519Key; if (der == NULL) der = ssl->ctx->staticKE.x25519Key; if (der != NULL) { curve25519_key* key = (curve25519_key*)keyPtr; WOLFSSL_MSG("Using static X25519 key"); ret = wc_Curve25519PrivateKeyDecode(der->buffer, &idx, key, der->length); } break; #endif #ifdef HAVE_CURVE448 case WC_PK_TYPE_CURVE448: if (ssl != NULL) der = ssl->staticKE.x448Key; if (der == NULL) der = ssl->ctx->staticKE.x448Key; if (der != NULL) { curve448_key* key = (curve448_key*)keyPtr; WOLFSSL_MSG("Using static X448 key"); ret = wc_Curve448PrivateKeyDecode(der->buffer, &idx, key, der->length); } break; #endif default: /* not supported */ ret = NOT_COMPILED_IN; break; } #ifndef SINGLE_THREADED wc_UnLockMutex(&ssl->ctx->staticKELock); #endif return ret; } static int SetStaticEphemeralKey(WOLFSSL_CTX* ctx, StaticKeyExchangeInfo_t* staticKE, int keyAlgo, const char* key, unsigned int keySz, int format, void* heap) { int ret = 0; DerBuffer* der = NULL; byte* keyBuf = NULL; #ifndef NO_FILESYSTEM const char* keyFile = NULL; #endif /* allow empty key to free buffer */ if (staticKE == NULL || (key == NULL && keySz > 0)) { return BAD_FUNC_ARG; } WOLFSSL_ENTER("SetStaticEphemeralKey"); /* if just free'ing key then skip loading */ if (key != NULL) { #ifndef NO_FILESYSTEM /* load file from filesystem */ if (key != NULL && keySz == 0) { size_t keyBufSz = 0; keyFile = (const char*)key; ret = wc_FileLoad(keyFile, &keyBuf, &keyBufSz, heap); if (ret != 0) { return ret; } keySz = (unsigned int)keyBufSz; } else #endif { /* use as key buffer directly */ keyBuf = (byte*)key; } if (format == WOLFSSL_FILETYPE_PEM) { #ifdef WOLFSSL_PEM_TO_DER int keyFormat = 0; ret = PemToDer(keyBuf, keySz, PRIVATEKEY_TYPE, &der, heap, NULL, &keyFormat); /* auto detect key type */ if (ret == 0 && keyAlgo == WC_PK_TYPE_NONE) { if (keyFormat == ECDSAk) keyAlgo = WC_PK_TYPE_ECDH; else if (keyFormat == X25519k) keyAlgo = WC_PK_TYPE_CURVE25519; else keyAlgo = WC_PK_TYPE_DH; } #else ret = NOT_COMPILED_IN; #endif } else { /* Detect PK type (if required) */ #ifdef HAVE_ECC if (keyAlgo == WC_PK_TYPE_NONE) { word32 idx = 0; ecc_key eccKey; ret = wc_ecc_init_ex(&eccKey, heap, INVALID_DEVID); if (ret == 0) { ret = wc_EccPrivateKeyDecode(keyBuf, &idx, &eccKey, keySz); if (ret == 0) keyAlgo = WC_PK_TYPE_ECDH; wc_ecc_free(&eccKey); } } #endif #if !defined(NO_DH) && defined(WOLFSSL_DH_EXTRA) if (keyAlgo == WC_PK_TYPE_NONE) { word32 idx = 0; DhKey dhKey; ret = wc_InitDhKey_ex(&dhKey, heap, INVALID_DEVID); if (ret == 0) { ret = wc_DhKeyDecode(keyBuf, &idx, &dhKey, keySz); if (ret == 0) keyAlgo = WC_PK_TYPE_DH; wc_FreeDhKey(&dhKey); } } #endif #ifdef HAVE_CURVE25519 if (keyAlgo == WC_PK_TYPE_NONE) { word32 idx = 0; curve25519_key x25519Key; ret = wc_curve25519_init_ex(&x25519Key, heap, INVALID_DEVID); if (ret == 0) { ret = wc_Curve25519PrivateKeyDecode(keyBuf, &idx, &x25519Key, keySz); if (ret == 0) keyAlgo = WC_PK_TYPE_CURVE25519; wc_curve25519_free(&x25519Key); } } #endif #ifdef HAVE_CURVE448 if (keyAlgo == WC_PK_TYPE_NONE) { word32 idx = 0; curve448_key x448Key; ret = wc_curve448_init(&x448Key); if (ret == 0) { ret = wc_Curve448PrivateKeyDecode(keyBuf, &idx, &x448Key, keySz); if (ret == 0) keyAlgo = WC_PK_TYPE_CURVE448; wc_curve448_free(&x448Key); } } #endif if (keyAlgo != WC_PK_TYPE_NONE) { ret = AllocDer(&der, keySz, PRIVATEKEY_TYPE, heap); if (ret == 0) { XMEMCPY(der->buffer, keyBuf, keySz); } } } } #ifndef NO_FILESYSTEM /* done with keyFile buffer */ if (keyFile && keyBuf) { XFREE(keyBuf, heap, DYNAMIC_TYPE_TMP_BUFFER); } #endif #ifndef SINGLE_THREADED if (ret == 0 && !ctx->staticKELockInit) { ret = wc_InitMutex(&ctx->staticKELock); if (ret == 0) { ctx->staticKELockInit = 1; } } #endif if (ret == 0 #ifndef SINGLE_THREADED && (ret = wc_LockMutex(&ctx->staticKELock)) == 0 #endif ) { switch (keyAlgo) { #ifndef NO_DH case WC_PK_TYPE_DH: FreeDer(&staticKE->dhKey); staticKE->dhKey = der; der = NULL; break; #endif #ifdef HAVE_ECC case WC_PK_TYPE_ECDH: FreeDer(&staticKE->ecKey); staticKE->ecKey = der; der = NULL; break; #endif #ifdef HAVE_CURVE25519 case WC_PK_TYPE_CURVE25519: FreeDer(&staticKE->x25519Key); staticKE->x25519Key = der; der = NULL; break; #endif #ifdef HAVE_CURVE448 case WC_PK_TYPE_CURVE448: FreeDer(&staticKE->x448Key); staticKE->x448Key = der; der = NULL; break; #endif default: /* not supported */ ret = NOT_COMPILED_IN; break; } #ifndef SINGLE_THREADED wc_UnLockMutex(&ctx->staticKELock); #endif } if (ret != 0) { FreeDer(&der); } (void)ctx; /* not used for single threaded */ WOLFSSL_LEAVE("SetStaticEphemeralKey", ret); return ret; } int wolfSSL_CTX_set_ephemeral_key(WOLFSSL_CTX* ctx, int keyAlgo, const char* key, unsigned int keySz, int format) { if (ctx == NULL) { return BAD_FUNC_ARG; } return SetStaticEphemeralKey(ctx, &ctx->staticKE, keyAlgo, key, keySz, format, ctx->heap); } int wolfSSL_set_ephemeral_key(WOLFSSL* ssl, int keyAlgo, const char* key, unsigned int keySz, int format) { if (ssl == NULL || ssl->ctx == NULL) { return BAD_FUNC_ARG; } return SetStaticEphemeralKey(ssl->ctx, &ssl->staticKE, keyAlgo, key, keySz, format, ssl->heap); } static int GetStaticEphemeralKey(WOLFSSL_CTX* ctx, WOLFSSL* ssl, int keyAlgo, const unsigned char** key, unsigned int* keySz) { int ret = 0; DerBuffer* der = NULL; if (key) *key = NULL; if (keySz) *keySz = 0; #ifndef SINGLE_THREADED if (ctx->staticKELockInit && (ret = wc_LockMutex(&ctx->staticKELock)) != 0) { return ret; } #endif switch (keyAlgo) { #ifndef NO_DH case WC_PK_TYPE_DH: if (ssl != NULL) der = ssl->staticKE.dhKey; if (der == NULL) der = ctx->staticKE.dhKey; break; #endif #ifdef HAVE_ECC case WC_PK_TYPE_ECDH: if (ssl != NULL) der = ssl->staticKE.ecKey; if (der == NULL) der = ctx->staticKE.ecKey; break; #endif #ifdef HAVE_CURVE25519 case WC_PK_TYPE_CURVE25519: if (ssl != NULL) der = ssl->staticKE.x25519Key; if (der == NULL) der = ctx->staticKE.x25519Key; break; #endif #ifdef HAVE_CURVE448 case WC_PK_TYPE_CURVE448: if (ssl != NULL) der = ssl->staticKE.x448Key; if (der == NULL) der = ctx->staticKE.x448Key; break; #endif default: /* not supported */ ret = NOT_COMPILED_IN; break; } if (der) { if (key) *key = der->buffer; if (keySz) *keySz = der->length; } #ifndef SINGLE_THREADED wc_UnLockMutex(&ctx->staticKELock); #endif return ret; } /* returns pointer to currently loaded static ephemeral as ASN.1 */ /* this can be converted to PEM using wc_DerToPem */ int wolfSSL_CTX_get_ephemeral_key(WOLFSSL_CTX* ctx, int keyAlgo, const unsigned char** key, unsigned int* keySz) { if (ctx == NULL) { return BAD_FUNC_ARG; } return GetStaticEphemeralKey(ctx, NULL, keyAlgo, key, keySz); } int wolfSSL_get_ephemeral_key(WOLFSSL* ssl, int keyAlgo, const unsigned char** key, unsigned int* keySz) { if (ssl == NULL || ssl->ctx == NULL) { return BAD_FUNC_ARG; } return GetStaticEphemeralKey(ssl->ctx, ssl, keyAlgo, key, keySz); } #endif /* WOLFSSL_STATIC_EPHEMERAL */ #if defined(OPENSSL_EXTRA) /* wolfSSL_THREADID_current is provided as a compat API with * CRYPTO_THREADID_current to register current thread id into given id object. * However, CRYPTO_THREADID_current API has been deprecated and no longer * exists in the OpenSSL 1.0.0 or later.This API only works as a stub * like as existing wolfSSL_THREADID_set_numeric. */ void wolfSSL_THREADID_current(WOLFSSL_CRYPTO_THREADID* id) { (void)id; return; } /* wolfSSL_THREADID_hash is provided as a compatible API with * CRYPTO_THREADID_hash which returns a hash value calcurated from the * specified thread id. However, CRYPTO_THREADID_hash API has been * deprecated and no longer exists in the OpenSSL 1.0.0 or later. * This API only works as a stub to returns 0. This behavior is * equivalent to the latest OpenSSL CRYPTO_THREADID_hash. */ unsigned long wolfSSL_THREADID_hash(const WOLFSSL_CRYPTO_THREADID* id) { (void)id; return 0UL; } /* wolfSSL_CTX_set_ecdh_auto is provided as compatible API with * SSL_CTX_set_ecdh_auto to enable auto ecdh curve selection functionality. * Since this functionality is enabled by default in wolfSSL, * this API exists as a stub. */ int wolfSSL_CTX_set_ecdh_auto(WOLFSSL_CTX* ctx, int onoff) { (void)ctx; (void)onoff; return WOLFSSL_SUCCESS; } /** * set security level (wolfSSL doesn't support security level) * @param ctx a pointer to WOLFSSL_EVP_PKEY_CTX structure * @param level security level */ void wolfSSL_CTX_set_security_level(WOLFSSL_CTX* ctx, int level) { WOLFSSL_ENTER("wolfSSL_CTX_set_security_level"); (void)ctx; (void)level; } /** * get security level (wolfSSL doesn't support security level) * @param ctx a pointer to WOLFSSL_EVP_PKEY_CTX structure * @return always 0(level 0) */ int wolfSSL_CTX_get_security_level(const WOLFSSL_CTX* ctx) { WOLFSSL_ENTER("wolfSSL_CTX_get_security_level"); (void)ctx; return 0; } /** * Determine whether a WOLFSSL_SESSION object can be used for resumption * @param s a pointer to WOLFSSL_SESSION structure * @return return 1 if session is resumable, otherwise 0. */ int wolfSSL_SESSION_is_resumable(const WOLFSSL_SESSION *s) { s = ClientSessionToSession(s); if (s == NULL) return 0; #ifdef HAVE_SESSION_TICKET if (s->ticketLen > 0) return 1; #endif if (s->sessionIDSz > 0) return 1; return 0; } #if defined(OPENSSL_EXTRA) && defined(HAVE_SECRET_CALLBACK) /* * This API accepts a user callback which puts key-log records into * a KEY LOGFILE. The callback is stored into a CTX and propagated to * each SSL object on its creation timing. */ void wolfSSL_CTX_set_keylog_callback(WOLFSSL_CTX* ctx, wolfSSL_CTX_keylog_cb_func cb) { WOLFSSL_ENTER("wolfSSL_CTX_set_keylog_callback"); /* stores the callback into WOLFSSL_CTX */ if (ctx != NULL) { ctx->keyLogCb = cb; } } wolfSSL_CTX_keylog_cb_func wolfSSL_CTX_get_keylog_callback( const WOLFSSL_CTX* ctx) { WOLFSSL_ENTER("wolfSSL_CTX_get_keylog_callback"); if (ctx != NULL) return ctx->keyLogCb; else return NULL; } #endif /* OPENSSL_EXTRA && HAVE_SECRET_CALLBACK */ #endif /* OPENSSL_EXTRA */ #ifndef NO_CERT #define WOLFSSL_X509_INCLUDED #include "src/x509.c" #endif /******************************************************************************* * START OF standard C library wrapping APIs ******************************************************************************/ #if defined(OPENSSL_ALL) || (defined(OPENSSL_EXTRA) && (defined(HAVE_STUNNEL) || \ defined(WOLFSSL_NGINX) || defined(HAVE_LIGHTY) || \ defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_OPENSSH))) #ifndef NO_WOLFSSL_STUB int wolfSSL_CRYPTO_set_mem_ex_functions(void *(*m) (size_t, const char *, int), void *(*r) (void *, size_t, const char *, int), void (*f) (void *)) { (void) m; (void) r; (void) f; WOLFSSL_ENTER("wolfSSL_CRYPTO_set_mem_ex_functions"); WOLFSSL_STUB("CRYPTO_set_mem_ex_functions"); return WOLFSSL_FAILURE; } #endif #endif #if defined(OPENSSL_EXTRA) /** * free allocated memory resouce * @param str a pointer to resource to be freed * @param file dummy argument * @param line dummy argument */ void wolfSSL_CRYPTO_free(void *str, const char *file, int line) { (void)file; (void)line; XFREE(str, 0, DYNAMIC_TYPE_TMP_BUFFER); } /** * allocate memory with size of num * @param num size of memory allocation to be malloced * @param file dummy argument * @param line dummy argument * @return a pointer to allocated memory on succssesful, otherwise NULL */ void *wolfSSL_CRYPTO_malloc(size_t num, const char *file, int line) { (void)file; (void)line; return XMALLOC(num, 0, DYNAMIC_TYPE_TMP_BUFFER); } #endif /******************************************************************************* * END OF standard C library wrapping APIs ******************************************************************************/ /******************************************************************************* * START OF EX_DATA APIs ******************************************************************************/ #if defined(OPENSSL_ALL) || (defined(OPENSSL_EXTRA) && (defined(HAVE_STUNNEL) || \ defined(WOLFSSL_NGINX) || defined(HAVE_LIGHTY) || \ defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_OPENSSH))) void wolfSSL_CRYPTO_cleanup_all_ex_data(void){ WOLFSSL_ENTER("CRYPTO_cleanup_all_ex_data"); } #endif #ifdef HAVE_EX_DATA void* wolfSSL_CRYPTO_get_ex_data(const WOLFSSL_CRYPTO_EX_DATA* ex_data, int idx) { WOLFSSL_ENTER("wolfSSL_CTX_get_ex_data"); #ifdef MAX_EX_DATA if(ex_data && idx < MAX_EX_DATA && idx >= 0) { return ex_data->ex_data[idx]; } #else (void)ex_data; (void)idx; #endif return NULL; } int wolfSSL_CRYPTO_set_ex_data(WOLFSSL_CRYPTO_EX_DATA* ex_data, int idx, void *data) { WOLFSSL_ENTER("wolfSSL_CRYPTO_set_ex_data"); #ifdef MAX_EX_DATA if (ex_data && idx < MAX_EX_DATA && idx >= 0) { #ifdef HAVE_EX_DATA_CLEANUP_HOOKS if (ex_data->ex_data_cleanup_routines[idx]) { if (ex_data->ex_data[idx]) ex_data->ex_data_cleanup_routines[idx](ex_data->ex_data[idx]); ex_data->ex_data_cleanup_routines[idx] = NULL; } #endif ex_data->ex_data[idx] = data; return WOLFSSL_SUCCESS; } #else (void)ex_data; (void)idx; (void)data; #endif return WOLFSSL_FAILURE; } #ifdef HAVE_EX_DATA_CLEANUP_HOOKS int wolfSSL_CRYPTO_set_ex_data_with_cleanup( WOLFSSL_CRYPTO_EX_DATA* ex_data, int idx, void *data, wolfSSL_ex_data_cleanup_routine_t cleanup_routine) { WOLFSSL_ENTER("wolfSSL_CRYPTO_set_ex_data_with_cleanup"); if (ex_data && idx < MAX_EX_DATA && idx >= 0) { if (ex_data->ex_data_cleanup_routines[idx] && ex_data->ex_data[idx]) ex_data->ex_data_cleanup_routines[idx](ex_data->ex_data[idx]); ex_data->ex_data[idx] = data; ex_data->ex_data_cleanup_routines[idx] = cleanup_routine; return WOLFSSL_SUCCESS; } return WOLFSSL_FAILURE; } #endif /* HAVE_EX_DATA_CLEANUP_HOOKS */ /** * Issues unique index for the class specified by class_index. * Other parameter except class_index are ignored. * Currently, following class_index are accepted: * - WOLF_CRYPTO_EX_INDEX_SSL * - WOLF_CRYPTO_EX_INDEX_SSL_CTX * - WOLF_CRYPTO_EX_INDEX_X509 * @param class_index index one of CRYPTO_EX_INDEX_xxx * @param argp parameters to be saved * @param argl parameters to be saved * @param new_func a pointer to WOLFSSL_CRYPTO_EX_new * @param dup_func a pointer to WOLFSSL_CRYPTO_EX_dup * @param free_func a pointer to WOLFSSL_CRYPTO_EX_free * @return index value grater or equal to zero on success, -1 on failure. */ int wolfSSL_CRYPTO_get_ex_new_index(int class_index, long argl, void *argp, WOLFSSL_CRYPTO_EX_new* new_func, WOLFSSL_CRYPTO_EX_dup* dup_func, WOLFSSL_CRYPTO_EX_free* free_func) { WOLFSSL_ENTER("wolfSSL_CRYPTO_get_ex_new_index"); (void)argl; (void)argp; (void)new_func; (void)dup_func; (void)free_func; return wolfssl_get_ex_new_index(class_index); } #endif /* HAVE_EX_DATA */ /******************************************************************************* * END OF EX_DATA APIs ******************************************************************************/ /******************************************************************************* * START OF BUF_MEM API ******************************************************************************/ #if defined(OPENSSL_EXTRA) /* Begin functions for openssl/buffer.h */ WOLFSSL_BUF_MEM* wolfSSL_BUF_MEM_new(void) { WOLFSSL_BUF_MEM* buf; buf = (WOLFSSL_BUF_MEM*)XMALLOC(sizeof(WOLFSSL_BUF_MEM), NULL, DYNAMIC_TYPE_OPENSSL); if (buf) { XMEMSET(buf, 0, sizeof(WOLFSSL_BUF_MEM)); } return buf; } /* non-compat API returns length of buffer on success */ int wolfSSL_BUF_MEM_grow_ex(WOLFSSL_BUF_MEM* buf, size_t len, char zeroFill) { int len_int = (int)len; int mx; char* tmp; /* verify provided arguments */ if (buf == NULL || len_int < 0) { return 0; /* BAD_FUNC_ARG; */ } /* check to see if fits in existing length */ if (buf->length > len) { buf->length = len; return len_int; } /* check to see if fits in max buffer */ if (buf->max >= len) { if (buf->data != NULL && zeroFill) { XMEMSET(&buf->data[buf->length], 0, len - buf->length); } buf->length = len; return len_int; } /* expand size, to handle growth */ mx = (len_int + 3) / 3 * 4; /* use realloc */ tmp = (char*)XREALLOC(buf->data, mx, NULL, DYNAMIC_TYPE_OPENSSL); if (tmp == NULL) { return 0; /* ERR_R_MALLOC_FAILURE; */ } buf->data = tmp; buf->max = mx; if (zeroFill) XMEMSET(&buf->data[buf->length], 0, len - buf->length); buf->length = len; return len_int; } /* returns length of buffer on success */ int wolfSSL_BUF_MEM_grow(WOLFSSL_BUF_MEM* buf, size_t len) { return wolfSSL_BUF_MEM_grow_ex(buf, len, 1); } /* non-compat API returns length of buffer on success */ int wolfSSL_BUF_MEM_resize(WOLFSSL_BUF_MEM* buf, size_t len) { char* tmp; int mx; /* verify provided arguments */ if (buf == NULL || len == 0 || (int)len <= 0) { return 0; /* BAD_FUNC_ARG; */ } if (len == buf->length) return (int)len; if (len > buf->length) return wolfSSL_BUF_MEM_grow_ex(buf, len, 0); /* expand size, to handle growth */ mx = ((int)len + 3) / 3 * 4; /* We want to shrink the internal buffer */ tmp = (char*)XREALLOC(buf->data, mx, NULL, DYNAMIC_TYPE_OPENSSL); if (tmp == NULL) return 0; buf->data = tmp; buf->length = len; buf->max = mx; return (int)len; } void wolfSSL_BUF_MEM_free(WOLFSSL_BUF_MEM* buf) { if (buf) { if (buf->data) { XFREE(buf->data, NULL, DYNAMIC_TYPE_OPENSSL); buf->data = NULL; } buf->max = 0; buf->length = 0; XFREE(buf, NULL, DYNAMIC_TYPE_OPENSSL); } } /* End Functions for openssl/buffer.h */ #endif /* OPENSSL_EXTRA */ /******************************************************************************* * END OF BUF_MEM API ******************************************************************************/ #define WOLFSSL_CONF_INCLUDED #include /******************************************************************************* * START OF RAND API ******************************************************************************/ #if defined(OPENSSL_EXTRA) && !defined(WOLFSSL_NO_OPENSSL_RAND_CB) static int wolfSSL_RAND_InitMutex(void) { if (gRandMethodsInit == 0) { if (wc_InitMutex(&gRandMethodMutex) != 0) { WOLFSSL_MSG("Bad Init Mutex rand methods"); return BAD_MUTEX_E; } gRandMethodsInit = 1; } return 0; } #endif #ifdef OPENSSL_EXTRA /* Checks if the global RNG has been created. If not then one is created. * * Returns WOLFSSL_SUCCESS when no error is encountered. */ int wolfSSL_RAND_Init(void) { int ret = WOLFSSL_FAILURE; #ifdef HAVE_GLOBAL_RNG if (wc_LockMutex(&globalRNGMutex) == 0) { if (initGlobalRNG == 0) { ret = wc_InitRng(&globalRNG); if (ret == 0) { initGlobalRNG = 1; ret = WOLFSSL_SUCCESS; } } wc_UnLockMutex(&globalRNGMutex); } #endif return ret; } /* WOLFSSL_SUCCESS on ok */ int wolfSSL_RAND_seed(const void* seed, int len) { #ifndef WOLFSSL_NO_OPENSSL_RAND_CB if (wolfSSL_RAND_InitMutex() == 0 && wc_LockMutex(&gRandMethodMutex) == 0) { if (gRandMethods && gRandMethods->seed) { int ret = gRandMethods->seed(seed, len); wc_UnLockMutex(&gRandMethodMutex); return ret; } wc_UnLockMutex(&gRandMethodMutex); } #else (void)seed; (void)len; #endif /* Make sure global shared RNG (globalRNG) is initialized */ return wolfSSL_RAND_Init(); } /* Returns the path for reading seed data from. * Uses the env variable $RANDFILE first if set, if not then used $HOME/.rnd * * Note uses stdlib by default unless XGETENV macro is overwritten * * fname buffer to hold path * len length of fname buffer * * Returns a pointer to fname on success and NULL on failure */ const char* wolfSSL_RAND_file_name(char* fname, unsigned long len) { #ifndef NO_FILESYSTEM char* rt; char ap[] = "/.rnd"; WOLFSSL_ENTER("wolfSSL_RAND_file_name"); if (fname == NULL) { return NULL; } XMEMSET(fname, 0, len); /* if access to stdlib.h */ if ((rt = XGETENV("RANDFILE")) != NULL) { if (len > XSTRLEN(rt)) { XMEMCPY(fname, rt, XSTRLEN(rt)); } else { WOLFSSL_MSG("RANDFILE too large for buffer"); rt = NULL; } } /* $RANDFILE was not set or is too large, check $HOME */ if (rt == NULL) { WOLFSSL_MSG("Environment variable RANDFILE not set"); if ((rt = XGETENV("HOME")) == NULL) { WOLFSSL_MSG("Environment variable HOME not set"); return NULL; } if (len > XSTRLEN(rt) + XSTRLEN(ap)) { fname[0] = '\0'; XSTRNCAT(fname, rt, len); XSTRNCAT(fname, ap, len - XSTRLEN(rt)); return fname; } else { WOLFSSL_MSG("HOME too large for buffer"); return NULL; } } return fname; #else /* no filesystem defined */ WOLFSSL_ENTER("wolfSSL_RAND_file_name"); WOLFSSL_MSG("No filesystem feature enabled, not compiled in"); (void)fname; (void)len; return NULL; #endif } /* Writes 1024 bytes from the RNG to the given file name. * * fname name of file to write to * * Returns the number of bytes written */ int wolfSSL_RAND_write_file(const char* fname) { int bytes = 0; WOLFSSL_ENTER("RAND_write_file"); if (fname == NULL) { return SSL_FAILURE; } #ifndef NO_FILESYSTEM { #ifndef WOLFSSL_SMALL_STACK unsigned char buf[1024]; #else unsigned char* buf = (unsigned char *)XMALLOC(1024, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (buf == NULL) { WOLFSSL_MSG("malloc failed"); return SSL_FAILURE; } #endif bytes = 1024; /* default size of buf */ if (initGlobalRNG == 0 && wolfSSL_RAND_Init() != WOLFSSL_SUCCESS) { WOLFSSL_MSG("No RNG to use"); #ifdef WOLFSSL_SMALL_STACK XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return 0; } if (wc_RNG_GenerateBlock(&globalRNG, buf, bytes) != 0) { WOLFSSL_MSG("Error generating random buffer"); bytes = 0; } else { XFILE f; #ifdef WOLFSSL_CHECK_MEM_ZERO wc_MemZero_Add("wolfSSL_RAND_write_file buf", buf, bytes); #endif f = XFOPEN(fname, "wb"); if (f == XBADFILE) { WOLFSSL_MSG("Error opening the file"); bytes = 0; } else { XFWRITE(buf, 1, bytes, f); XFCLOSE(f); } } ForceZero(buf, bytes); #ifdef WOLFSSL_SMALL_STACK XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); #elif defined(WOLFSSL_CHECK_MEM_ZERO) wc_MemZero_Check(buf, sizeof(buf)); #endif } #endif return bytes; } #ifndef FREERTOS_TCP /* These constant values are protocol values made by egd */ #if defined(USE_WOLFSSL_IO) && !defined(USE_WINDOWS_API) && !defined(HAVE_FIPS) && \ defined(HAVE_HASHDRBG) && !defined(NETOS) && defined(HAVE_SYS_UN_H) #define WOLFSSL_EGD_NBLOCK 0x01 #include #endif /* This collects entropy from the path nm and seeds the global PRNG with it. * * nm is the file path to the egd server * * Returns the number of bytes read. */ int wolfSSL_RAND_egd(const char* nm) { #ifdef WOLFSSL_EGD_NBLOCK struct sockaddr_un rem; int fd; int ret = WOLFSSL_SUCCESS; word32 bytes = 0; word32 idx = 0; #ifndef WOLFSSL_SMALL_STACK unsigned char buf[256]; #else unsigned char* buf; buf = (unsigned char*)XMALLOC(256, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (buf == NULL) { WOLFSSL_MSG("Not enough memory"); return WOLFSSL_FATAL_ERROR; } #endif XMEMSET(&rem, 0, sizeof(struct sockaddr_un)); if (nm == NULL) { #ifdef WOLFSSL_SMALL_STACK XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return WOLFSSL_FATAL_ERROR; } fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd < 0) { WOLFSSL_MSG("Error creating socket"); #ifdef WOLFSSL_SMALL_STACK XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return WOLFSSL_FATAL_ERROR; } rem.sun_family = AF_UNIX; XSTRNCPY(rem.sun_path, nm, sizeof(rem.sun_path) - 1); rem.sun_path[sizeof(rem.sun_path)-1] = '\0'; /* connect to egd server */ if (connect(fd, (struct sockaddr*)&rem, sizeof(struct sockaddr_un)) == -1) { WOLFSSL_MSG("error connecting to egd server"); ret = WOLFSSL_FATAL_ERROR; } #ifdef WOLFSSL_CHECK_MEM_ZERO if (ret == WOLFSSL_SUCCESS) { wc_MemZero_Add("wolfSSL_RAND_egd buf", buf, 256); } #endif while (ret == WOLFSSL_SUCCESS && bytes < 255 && idx + 2 < 256) { buf[idx] = WOLFSSL_EGD_NBLOCK; buf[idx + 1] = 255 - bytes; /* request 255 bytes from server */ ret = (int)write(fd, buf + idx, 2); if (ret != 2) { if (errno == EAGAIN) { ret = WOLFSSL_SUCCESS; continue; } WOLFSSL_MSG("error requesting entropy from egd server"); ret = WOLFSSL_FATAL_ERROR; break; } /* attempting to read */ buf[idx] = 0; ret = (int)read(fd, buf + idx, 256 - bytes); if (ret == 0) { WOLFSSL_MSG("error reading entropy from egd server"); ret = WOLFSSL_FATAL_ERROR; break; } if (ret > 0 && buf[idx] > 0) { bytes += buf[idx]; /* egd stores amount sent in first byte */ if (bytes + idx > 255 || buf[idx] > ret) { WOLFSSL_MSG("Buffer error"); ret = WOLFSSL_FATAL_ERROR; break; } XMEMMOVE(buf + idx, buf + idx + 1, buf[idx]); idx = bytes; ret = WOLFSSL_SUCCESS; if (bytes >= 255) { break; } } else { if (errno == EAGAIN || errno == EINTR) { WOLFSSL_MSG("EGD would read"); ret = WOLFSSL_SUCCESS; /* try again */ } else if (buf[idx] == 0) { /* if egd returned 0 then there is no more entropy to be had. Do not try more reads. */ ret = WOLFSSL_SUCCESS; break; } else { WOLFSSL_MSG("Error with read"); ret = WOLFSSL_FATAL_ERROR; } } } if (bytes > 0 && ret == WOLFSSL_SUCCESS) { /* call to check global RNG is created */ if (wolfSSL_RAND_Init() != SSL_SUCCESS) { WOLFSSL_MSG("Error with initializing global RNG structure"); ret = WOLFSSL_FATAL_ERROR; } else if (wc_RNG_DRBG_Reseed(&globalRNG, (const byte*) buf, bytes) != 0) { WOLFSSL_MSG("Error with reseeding DRBG structure"); ret = WOLFSSL_FATAL_ERROR; } #ifdef SHOW_SECRETS else { /* print out entropy found only when no error occured */ word32 i; printf("EGD Entropy = "); for (i = 0; i < bytes; i++) { printf("%02X", buf[i]); } printf("\n"); } #endif } ForceZero(buf, bytes); #ifdef WOLFSSL_SMALL_STACK XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); #elif defined(WOLFSSL_CHECK_MEM_ZERO) wc_MemZero_Check(buf, 256); #endif close(fd); if (ret == WOLFSSL_SUCCESS) { return bytes; } else { return ret; } #else WOLFSSL_MSG("Type of socket needed is not available"); WOLFSSL_MSG("\tor using mode where DRBG API is not available"); (void)nm; return WOLFSSL_FATAL_ERROR; #endif /* WOLFSSL_EGD_NBLOCK */ } #endif /* !FREERTOS_TCP */ void wolfSSL_RAND_Cleanup(void) { #ifndef WOLFSSL_NO_OPENSSL_RAND_CB if (wolfSSL_RAND_InitMutex() == 0 && wc_LockMutex(&gRandMethodMutex) == 0) { if (gRandMethods && gRandMethods->cleanup) gRandMethods->cleanup(); wc_UnLockMutex(&gRandMethodMutex); } if (wc_FreeMutex(&gRandMethodMutex) == 0) gRandMethodsInit = 0; #endif #ifdef HAVE_GLOBAL_RNG if (wc_LockMutex(&globalRNGMutex) == 0) { if (initGlobalRNG) { wc_FreeRng(&globalRNG); initGlobalRNG = 0; } wc_UnLockMutex(&globalRNGMutex); } #endif } /* returns WOLFSSL_SUCCESS if the bytes generated are valid otherwise WOLFSSL_FAILURE */ int wolfSSL_RAND_pseudo_bytes(unsigned char* buf, int num) { int ret; int hash; byte secret[DRBG_SEED_LEN]; /* secret length arbitraily choosen */ #ifndef WOLFSSL_NO_OPENSSL_RAND_CB if (wolfSSL_RAND_InitMutex() == 0 && wc_LockMutex(&gRandMethodMutex) == 0) { if (gRandMethods && gRandMethods->pseudorand) { ret = gRandMethods->pseudorand(buf, num); wc_UnLockMutex(&gRandMethodMutex); return ret; } wc_UnLockMutex(&gRandMethodMutex); } #endif #ifdef WOLFSSL_HAVE_PRF #ifndef NO_SHA256 hash = WC_SHA256; #elif defined(WOLFSSL_SHA384) hash = WC_SHA384; #elif !defined(NO_SHA) hash = WC_SHA; #elif !defined(NO_MD5) hash = WC_MD5; #endif /* get secret value from source of entropy */ ret = wolfSSL_RAND_bytes(secret, DRBG_SEED_LEN); /* uses input buffer to seed for pseudo random number generation, each * thread will potentially have different results this way */ if (ret == WOLFSSL_SUCCESS) { PRIVATE_KEY_UNLOCK(); ret = wc_PRF(buf, num, secret, DRBG_SEED_LEN, (const byte*)buf, num, hash, NULL, INVALID_DEVID); PRIVATE_KEY_LOCK(); ret = (ret == 0) ? WOLFSSL_SUCCESS: WOLFSSL_FAILURE; } #else /* fall back to just doing wolfSSL_RAND_bytes if PRF not avialbale */ ret = wolfSSL_RAND_bytes(buf, num); (void)hash; (void)secret; #endif return ret; } /* returns WOLFSSL_SUCCESS if the bytes generated are valid otherwise WOLFSSL_FAILURE */ int wolfSSL_RAND_bytes(unsigned char* buf, int num) { int ret = 0; WC_RNG* rng = NULL; #ifdef WOLFSSL_SMALL_STACK WC_RNG* tmpRNG = NULL; #else WC_RNG tmpRNG[1]; #endif int initTmpRng = 0; int blockCount = 0; #ifdef HAVE_GLOBAL_RNG int used_global = 0; #endif WOLFSSL_ENTER("wolfSSL_RAND_bytes"); /* sanity check */ if (buf == NULL || num < 0) /* return code compliant with OpenSSL */ return 0; /* if a RAND callback has been set try and use it */ #ifndef WOLFSSL_NO_OPENSSL_RAND_CB if (wolfSSL_RAND_InitMutex() == 0 && wc_LockMutex(&gRandMethodMutex) == 0) { if (gRandMethods && gRandMethods->bytes) { ret = gRandMethods->bytes(buf, num); wc_UnLockMutex(&gRandMethodMutex); return ret; } wc_UnLockMutex(&gRandMethodMutex); } #endif #ifdef HAVE_GLOBAL_RNG if (initGlobalRNG) { if (wc_LockMutex(&globalRNGMutex) != 0) { WOLFSSL_MSG("Bad Lock Mutex rng"); return ret; } rng = &globalRNG; used_global = 1; } else #endif { #ifdef WOLFSSL_SMALL_STACK tmpRNG = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG); if (tmpRNG == NULL) return ret; #endif if (wc_InitRng(tmpRNG) == 0) { rng = tmpRNG; initTmpRng = 1; } } if (rng) { /* handles size greater than RNG_MAX_BLOCK_LEN */ blockCount = num / RNG_MAX_BLOCK_LEN; while (blockCount--) { ret = wc_RNG_GenerateBlock(rng, buf, RNG_MAX_BLOCK_LEN); if (ret != 0) { WOLFSSL_MSG("Bad wc_RNG_GenerateBlock"); break; } num -= RNG_MAX_BLOCK_LEN; buf += RNG_MAX_BLOCK_LEN; } if (ret == 0 && num) ret = wc_RNG_GenerateBlock(rng, buf, num); if (ret != 0) WOLFSSL_MSG("Bad wc_RNG_GenerateBlock"); else ret = WOLFSSL_SUCCESS; } #ifdef HAVE_GLOBAL_RNG if (used_global == 1) wc_UnLockMutex(&globalRNGMutex); #endif if (initTmpRng) wc_FreeRng(tmpRNG); #ifdef WOLFSSL_SMALL_STACK if (tmpRNG) XFREE(tmpRNG, NULL, DYNAMIC_TYPE_RNG); #endif return ret; } int wolfSSL_RAND_poll(void) { byte entropy[16]; int ret = 0; word32 entropy_sz = 16; WOLFSSL_ENTER("wolfSSL_RAND_poll"); if (initGlobalRNG == 0){ WOLFSSL_MSG("Global RNG no Init"); return WOLFSSL_FAILURE; } ret = wc_GenerateSeed(&globalRNG.seed, entropy, entropy_sz); if (ret != 0){ WOLFSSL_MSG("Bad wc_RNG_GenerateBlock"); ret = WOLFSSL_FAILURE; }else ret = WOLFSSL_SUCCESS; return ret; } /* If a valid struct is provided with function pointers, will override RAND_seed, bytes, cleanup, add, pseudo_bytes and status. If a NULL pointer is passed in, it will cancel any previous function overrides. Returns WOLFSSL_SUCCESS on success, WOLFSSL_FAILURE on failure. */ int wolfSSL_RAND_set_rand_method(const WOLFSSL_RAND_METHOD *methods) { #ifndef WOLFSSL_NO_OPENSSL_RAND_CB if (wolfSSL_RAND_InitMutex() == 0 && wc_LockMutex(&gRandMethodMutex) == 0) { gRandMethods = methods; wc_UnLockMutex(&gRandMethodMutex); return WOLFSSL_SUCCESS; } #else (void)methods; #endif return WOLFSSL_FAILURE; } /* Returns WOLFSSL_SUCCESS if the RNG has been seeded with enough data */ int wolfSSL_RAND_status(void) { int ret = WOLFSSL_SUCCESS; #ifndef WOLFSSL_NO_OPENSSL_RAND_CB if (wolfSSL_RAND_InitMutex() == 0 && wc_LockMutex(&gRandMethodMutex) == 0) { if (gRandMethods && gRandMethods->status) ret = gRandMethods->status(); wc_UnLockMutex(&gRandMethodMutex); } else { ret = WOLFSSL_FAILURE; } #else /* wolfCrypt provides enough seed internally, so return success */ #endif return ret; } void wolfSSL_RAND_add(const void* add, int len, double entropy) { #ifndef WOLFSSL_NO_OPENSSL_RAND_CB if (wolfSSL_RAND_InitMutex() == 0 && wc_LockMutex(&gRandMethodMutex) == 0) { if (gRandMethods && gRandMethods->add) { /* callback has return code, but RAND_add does not */ (void)gRandMethods->add(add, len, entropy); } wc_UnLockMutex(&gRandMethodMutex); } #else /* wolfSSL seeds/adds internally, use explicit RNG if you want to take control */ (void)add; (void)len; (void)entropy; #endif } #endif /* OPENSSL_EXTRA */ /******************************************************************************* * END OF RAND API ******************************************************************************/ /******************************************************************************* * START OF EVP_CIPHER API ******************************************************************************/ #ifdef OPENSSL_EXTRA /* store for external read of iv, WOLFSSL_SUCCESS on success */ int wolfSSL_StoreExternalIV(WOLFSSL_EVP_CIPHER_CTX* ctx) { WOLFSSL_ENTER("wolfSSL_StoreExternalIV"); if (ctx == NULL) { WOLFSSL_MSG("Bad function argument"); return WOLFSSL_FATAL_ERROR; } switch (ctx->cipherType) { #ifndef NO_AES #if defined(HAVE_AES_CBC) || defined(WOLFSSL_AES_DIRECT) case AES_128_CBC_TYPE : case AES_192_CBC_TYPE : case AES_256_CBC_TYPE : WOLFSSL_MSG("AES CBC"); XMEMCPY(ctx->iv, &ctx->cipher.aes.reg, AES_BLOCK_SIZE); break; #endif #ifdef HAVE_AESGCM case AES_128_GCM_TYPE : case AES_192_GCM_TYPE : case AES_256_GCM_TYPE : WOLFSSL_MSG("AES GCM"); XMEMCPY(ctx->iv, &ctx->cipher.aes.reg, AES_BLOCK_SIZE); break; #endif /* HAVE_AESGCM */ #ifdef HAVE_AES_ECB case AES_128_ECB_TYPE : case AES_192_ECB_TYPE : case AES_256_ECB_TYPE : WOLFSSL_MSG("AES ECB"); break; #endif #ifdef WOLFSSL_AES_COUNTER case AES_128_CTR_TYPE : case AES_192_CTR_TYPE : case AES_256_CTR_TYPE : WOLFSSL_MSG("AES CTR"); XMEMCPY(ctx->iv, &ctx->cipher.aes.reg, AES_BLOCK_SIZE); break; #endif /* WOLFSSL_AES_COUNTER */ #ifdef WOLFSSL_AES_CFB #if !defined(HAVE_SELFTEST) && !defined(HAVE_FIPS) case AES_128_CFB1_TYPE: case AES_192_CFB1_TYPE: case AES_256_CFB1_TYPE: WOLFSSL_MSG("AES CFB1"); break; case AES_128_CFB8_TYPE: case AES_192_CFB8_TYPE: case AES_256_CFB8_TYPE: WOLFSSL_MSG("AES CFB8"); break; #endif /* !HAVE_SELFTEST && !HAVE_FIPS */ case AES_128_CFB128_TYPE: case AES_192_CFB128_TYPE: case AES_256_CFB128_TYPE: WOLFSSL_MSG("AES CFB128"); break; #endif /* WOLFSSL_AES_CFB */ #if defined(WOLFSSL_AES_OFB) case AES_128_OFB_TYPE: case AES_192_OFB_TYPE: case AES_256_OFB_TYPE: WOLFSSL_MSG("AES OFB"); break; #endif /* WOLFSSL_AES_OFB */ #ifdef WOLFSSL_AES_XTS case AES_128_XTS_TYPE: case AES_256_XTS_TYPE: WOLFSSL_MSG("AES XTS"); break; #endif /* WOLFSSL_AES_XTS */ #endif /* NO_AES */ #ifndef NO_DES3 case DES_CBC_TYPE : WOLFSSL_MSG("DES CBC"); XMEMCPY(ctx->iv, &ctx->cipher.des.reg, DES_BLOCK_SIZE); break; case DES_EDE3_CBC_TYPE : WOLFSSL_MSG("DES EDE3 CBC"); XMEMCPY(ctx->iv, &ctx->cipher.des3.reg, DES_BLOCK_SIZE); break; #endif #ifdef WOLFSSL_DES_ECB case DES_ECB_TYPE : WOLFSSL_MSG("DES ECB"); break; case DES_EDE3_ECB_TYPE : WOLFSSL_MSG("DES3 ECB"); break; #endif case ARC4_TYPE : WOLFSSL_MSG("ARC4"); break; #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) case CHACHA20_POLY1305_TYPE: break; #endif case NULL_CIPHER_TYPE : WOLFSSL_MSG("NULL"); break; default: { WOLFSSL_MSG("bad type"); return WOLFSSL_FATAL_ERROR; } } return WOLFSSL_SUCCESS; } /* set internal IV from external, WOLFSSL_SUCCESS on success */ int wolfSSL_SetInternalIV(WOLFSSL_EVP_CIPHER_CTX* ctx) { WOLFSSL_ENTER("wolfSSL_SetInternalIV"); if (ctx == NULL) { WOLFSSL_MSG("Bad function argument"); return WOLFSSL_FATAL_ERROR; } switch (ctx->cipherType) { #ifndef NO_AES #if defined(HAVE_AES_CBC) || defined(WOLFSSL_AES_DIRECT) case AES_128_CBC_TYPE : case AES_192_CBC_TYPE : case AES_256_CBC_TYPE : WOLFSSL_MSG("AES CBC"); XMEMCPY(&ctx->cipher.aes.reg, ctx->iv, AES_BLOCK_SIZE); break; #endif #ifdef HAVE_AESGCM case AES_128_GCM_TYPE : case AES_192_GCM_TYPE : case AES_256_GCM_TYPE : WOLFSSL_MSG("AES GCM"); XMEMCPY(&ctx->cipher.aes.reg, ctx->iv, AES_BLOCK_SIZE); break; #endif #ifdef HAVE_AES_ECB case AES_128_ECB_TYPE : case AES_192_ECB_TYPE : case AES_256_ECB_TYPE : WOLFSSL_MSG("AES ECB"); break; #endif #ifdef WOLFSSL_AES_COUNTER case AES_128_CTR_TYPE : case AES_192_CTR_TYPE : case AES_256_CTR_TYPE : WOLFSSL_MSG("AES CTR"); XMEMCPY(&ctx->cipher.aes.reg, ctx->iv, AES_BLOCK_SIZE); break; #endif #endif /* NO_AES */ #ifndef NO_DES3 case DES_CBC_TYPE : WOLFSSL_MSG("DES CBC"); XMEMCPY(&ctx->cipher.des.reg, ctx->iv, DES_BLOCK_SIZE); break; case DES_EDE3_CBC_TYPE : WOLFSSL_MSG("DES EDE3 CBC"); XMEMCPY(&ctx->cipher.des3.reg, ctx->iv, DES_BLOCK_SIZE); break; #endif #ifdef WOLFSSL_DES_ECB case DES_ECB_TYPE : WOLFSSL_MSG("DES ECB"); break; case DES_EDE3_ECB_TYPE : WOLFSSL_MSG("DES3 ECB"); break; #endif case ARC4_TYPE : WOLFSSL_MSG("ARC4"); break; #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) case CHACHA20_POLY1305_TYPE: break; #endif case NULL_CIPHER_TYPE : WOLFSSL_MSG("NULL"); break; default: { WOLFSSL_MSG("bad type"); return WOLFSSL_FATAL_ERROR; } } return WOLFSSL_SUCCESS; } #ifndef NO_DES3 void wolfSSL_3des_iv(WOLFSSL_EVP_CIPHER_CTX* ctx, int doset, unsigned char* iv, int len) { (void)len; WOLFSSL_MSG("wolfSSL_3des_iv"); if (ctx == NULL || iv == NULL) { WOLFSSL_MSG("Bad function argument"); return; } if (doset) wc_Des3_SetIV(&ctx->cipher.des3, iv); /* OpenSSL compat, no ret */ else XMEMCPY(iv, &ctx->cipher.des3.reg, DES_BLOCK_SIZE); } #endif /* NO_DES3 */ #ifndef NO_AES void wolfSSL_aes_ctr_iv(WOLFSSL_EVP_CIPHER_CTX* ctx, int doset, unsigned char* iv, int len) { (void)len; WOLFSSL_MSG("wolfSSL_aes_ctr_iv"); if (ctx == NULL || iv == NULL) { WOLFSSL_MSG("Bad function argument"); return; } if (doset) (void)wc_AesSetIV(&ctx->cipher.aes, iv); /* OpenSSL compat, no ret */ else XMEMCPY(iv, &ctx->cipher.aes.reg, AES_BLOCK_SIZE); } #endif /* NO_AES */ #endif /* OPENSSL_EXTRA */ /******************************************************************************* * END OF EVP_CIPHER API ******************************************************************************/ #ifndef NO_CERTS #define WOLFSSL_X509_STORE_INCLUDED #include /******************************************************************************* * START OF PKCS7 APIs ******************************************************************************/ #ifdef HAVE_PKCS7 #ifdef OPENSSL_ALL PKCS7* wolfSSL_PKCS7_new(void) { WOLFSSL_PKCS7* pkcs7; int ret = 0; pkcs7 = (WOLFSSL_PKCS7*)XMALLOC(sizeof(WOLFSSL_PKCS7), NULL, DYNAMIC_TYPE_PKCS7); if (pkcs7 != NULL) { XMEMSET(pkcs7, 0, sizeof(WOLFSSL_PKCS7)); ret = wc_PKCS7_Init(&pkcs7->pkcs7, NULL, INVALID_DEVID); } if (ret != 0 && pkcs7 != NULL) { XFREE(pkcs7, NULL, DYNAMIC_TYPE_PKCS7); pkcs7 = NULL; } return (PKCS7*)pkcs7; } /****************************************************************************** * wolfSSL_PKCS7_SIGNED_new - allocates PKCS7 and initialize it for a signed data * * RETURNS: * returns pointer to the PKCS7 structure on success, otherwise returns NULL */ PKCS7_SIGNED* wolfSSL_PKCS7_SIGNED_new(void) { byte signedData[]= { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02}; PKCS7* pkcs7 = NULL; if ((pkcs7 = wolfSSL_PKCS7_new()) == NULL) return NULL; pkcs7->contentOID = SIGNED_DATA; if ((wc_PKCS7_SetContentType(pkcs7, signedData, sizeof(signedData))) < 0) { if (pkcs7) { wolfSSL_PKCS7_free(pkcs7); return NULL; } } return pkcs7; } void wolfSSL_PKCS7_free(PKCS7* pkcs7) { WOLFSSL_PKCS7* p7 = (WOLFSSL_PKCS7*)pkcs7; if (p7 != NULL) { if (p7->data != NULL) XFREE(p7->data, NULL, DYNAMIC_TYPE_PKCS7); wc_PKCS7_Free(&p7->pkcs7); if (p7->certs) wolfSSL_sk_pop_free(p7->certs, NULL); XFREE(p7, NULL, DYNAMIC_TYPE_PKCS7); } } void wolfSSL_PKCS7_SIGNED_free(PKCS7_SIGNED* p7) { wolfSSL_PKCS7_free(p7); return; } /** * Convert DER/ASN.1 encoded signedData structure to internal PKCS7 * structure. Note, does not support detached content. * * p7 - pointer to set to address of newly created PKCS7 structure on return * in - pointer to pointer of DER/ASN.1 data * len - length of input data, bytes * * Returns newly allocated and populated PKCS7 structure or NULL on error. */ PKCS7* wolfSSL_d2i_PKCS7(PKCS7** p7, const unsigned char** in, int len) { return wolfSSL_d2i_PKCS7_ex(p7, in, len, NULL, 0); } /***************************************************************************** * wolfSSL_d2i_PKCS7_ex - Converts the given unsigned char buffer of size len * into a PKCS7 object. Optionally, accepts a byte buffer of content which * is stored as the PKCS7 object's content, to support detached signatures. * @param content The content which is signed, in case the signature is * detached. Ignored if NULL. * @param contentSz The size of the passed in content. * * RETURNS: * returns pointer to a PKCS7 structure on success, otherwise returns NULL */ PKCS7* wolfSSL_d2i_PKCS7_ex(PKCS7** p7, const unsigned char** in, int len, byte* content, word32 contentSz) { WOLFSSL_PKCS7* pkcs7 = NULL; WOLFSSL_ENTER("wolfSSL_d2i_PKCS7_ex"); if (in == NULL || *in == NULL || len < 0) return NULL; if ((pkcs7 = (WOLFSSL_PKCS7*)wolfSSL_PKCS7_new()) == NULL) return NULL; pkcs7->len = len; pkcs7->data = (byte*)XMALLOC(pkcs7->len, NULL, DYNAMIC_TYPE_PKCS7); if (pkcs7->data == NULL) { wolfSSL_PKCS7_free((PKCS7*)pkcs7); return NULL; } XMEMCPY(pkcs7->data, *in, pkcs7->len); if (content != NULL) { pkcs7->pkcs7.content = content; pkcs7->pkcs7.contentSz = contentSz; } if (wc_PKCS7_VerifySignedData(&pkcs7->pkcs7, pkcs7->data, pkcs7->len) != 0) { WOLFSSL_MSG("wc_PKCS7_VerifySignedData failed"); wolfSSL_PKCS7_free((PKCS7*)pkcs7); return NULL; } if (p7 != NULL) *p7 = (PKCS7*)pkcs7; *in += pkcs7->len; return (PKCS7*)pkcs7; } /** * This API was added as a helper function for libest. It * extracts a stack of certificates from the pkcs7 object. * @param pkcs7 PKCS7 parameter object * @return WOLFSSL_STACK_OF(WOLFSSL_X509)* */ WOLFSSL_STACK* wolfSSL_PKCS7_to_stack(PKCS7* pkcs7) { int i; WOLFSSL_PKCS7* p7 = (WOLFSSL_PKCS7*)pkcs7; WOLF_STACK_OF(WOLFSSL_X509)* ret = NULL; WOLFSSL_ENTER("wolfSSL_PKCS7_to_stack"); if (!p7) { WOLFSSL_MSG("Bad parameter"); return NULL; } if (p7->certs) return p7->certs; for (i = 0; i < MAX_PKCS7_CERTS && p7->pkcs7.cert[i]; i++) { WOLFSSL_X509* x509 = wolfSSL_X509_d2i(NULL, p7->pkcs7.cert[i], p7->pkcs7.certSz[i]); if (!ret) ret = wolfSSL_sk_X509_new(); if (x509) { if (wolfSSL_sk_X509_push(ret, x509) != WOLFSSL_SUCCESS) { wolfSSL_X509_free(x509); WOLFSSL_MSG("wolfSSL_sk_X509_push error"); goto error; } } else { WOLFSSL_MSG("wolfSSL_X509_d2i error"); goto error; } } /* Save stack to free later */ if (p7->certs) wolfSSL_sk_pop_free(p7->certs, NULL); p7->certs = ret; return ret; error: if (ret) { wolfSSL_sk_pop_free(ret, NULL); } return NULL; } /** * Return stack of signers contained in PKCS7 cert. * Notes: * - Currently only PKCS#7 messages with a single signer cert is supported. * - Returned WOLFSSL_STACK must be freed by caller. * * pkcs7 - PKCS7 struct to retrieve signer certs from. * certs - currently unused * flags - flags to control function behavior. * * Return WOLFSSL_STACK of signers on success, NULL on error. */ WOLFSSL_STACK* wolfSSL_PKCS7_get0_signers(PKCS7* pkcs7, WOLFSSL_STACK* certs, int flags) { WOLFSSL_X509* x509 = NULL; WOLFSSL_STACK* signers = NULL; WOLFSSL_PKCS7* p7 = (WOLFSSL_PKCS7*)pkcs7; if (p7 == NULL) return NULL; /* Only PKCS#7 messages with a single cert that is the verifying certificate * is supported. */ if (flags & PKCS7_NOINTERN) { WOLFSSL_MSG("PKCS7_NOINTERN flag not supported"); return NULL; } signers = wolfSSL_sk_X509_new(); if (signers == NULL) return NULL; if (wolfSSL_d2i_X509(&x509, (const byte**)&p7->pkcs7.singleCert, p7->pkcs7.singleCertSz) == NULL) { wolfSSL_sk_X509_pop_free(signers, NULL); return NULL; } if (wolfSSL_sk_X509_push(signers, x509) != WOLFSSL_SUCCESS) { wolfSSL_sk_X509_pop_free(signers, NULL); return NULL; } (void)certs; return signers; } #ifndef NO_BIO PKCS7* wolfSSL_d2i_PKCS7_bio(WOLFSSL_BIO* bio, PKCS7** p7) { WOLFSSL_PKCS7* pkcs7; int ret; WOLFSSL_ENTER("wolfSSL_d2i_PKCS7_bio"); if (bio == NULL) return NULL; if ((pkcs7 = (WOLFSSL_PKCS7*)wolfSSL_PKCS7_new()) == NULL) return NULL; pkcs7->len = wolfSSL_BIO_get_len(bio); pkcs7->data = (byte*)XMALLOC(pkcs7->len, NULL, DYNAMIC_TYPE_PKCS7); if (pkcs7->data == NULL) { wolfSSL_PKCS7_free((PKCS7*)pkcs7); return NULL; } if ((ret = wolfSSL_BIO_read(bio, pkcs7->data, pkcs7->len)) <= 0) { wolfSSL_PKCS7_free((PKCS7*)pkcs7); return NULL; } /* pkcs7->len may change if using b64 for example */ pkcs7->len = ret; if (wc_PKCS7_VerifySignedData(&pkcs7->pkcs7, pkcs7->data, pkcs7->len) != 0) { WOLFSSL_MSG("wc_PKCS7_VerifySignedData failed"); wolfSSL_PKCS7_free((PKCS7*)pkcs7); return NULL; } if (p7 != NULL) *p7 = (PKCS7*)pkcs7; return (PKCS7*)pkcs7; } int wolfSSL_i2d_PKCS7(PKCS7 *p7, unsigned char **out) { byte* output = NULL; int localBuf = 0; int len; WC_RNG rng; int ret = WOLFSSL_FAILURE; WOLFSSL_ENTER("wolfSSL_i2d_PKCS7"); if (!out || !p7) { WOLFSSL_MSG("Bad parameter"); return WOLFSSL_FAILURE; } if (!p7->rng) { if (wc_InitRng(&rng) != 0) { WOLFSSL_MSG("wc_InitRng error"); return WOLFSSL_FAILURE; } p7->rng = &rng; // cppcheck-suppress autoVariables } if ((len = wc_PKCS7_EncodeSignedData(p7, NULL, 0)) < 0) { WOLFSSL_MSG("wc_PKCS7_EncodeSignedData error"); goto cleanup; } if (*out == NULL) { output = (byte*)XMALLOC(len, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (!output) { WOLFSSL_MSG("malloc error"); goto cleanup; } localBuf = 1; } else { output = *out; } if ((len = wc_PKCS7_EncodeSignedData(p7, output, len)) < 0) { WOLFSSL_MSG("wc_PKCS7_EncodeSignedData error"); goto cleanup; } ret = len; cleanup: if (p7->rng == &rng) { wc_FreeRng(&rng); p7->rng = NULL; } if (ret == WOLFSSL_FAILURE && localBuf && output) XFREE(output, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (ret != WOLFSSL_FAILURE) *out = output; return ret; } int wolfSSL_i2d_PKCS7_bio(WOLFSSL_BIO *bio, PKCS7 *p7) { byte* output = NULL; int len; int ret = WOLFSSL_FAILURE; WOLFSSL_ENTER("wolfSSL_i2d_PKCS7_bio"); if (!bio || !p7) { WOLFSSL_MSG("Bad parameter"); return WOLFSSL_FAILURE; } if ((len = wolfSSL_i2d_PKCS7(p7, &output)) == WOLFSSL_FAILURE) { WOLFSSL_MSG("wolfSSL_i2d_PKCS7 error"); goto cleanup; } if (wolfSSL_BIO_write(bio, output, len) <= 0) { WOLFSSL_MSG("wolfSSL_BIO_write error"); goto cleanup; } ret = WOLFSSL_SUCCESS; cleanup: if (output) XFREE(output, NULL, DYNAMIC_TYPE_TMP_BUFFER); return ret; } /** * Creates and returns a PKCS7 signedData structure. * * Inner content type is set to DATA to match OpenSSL behavior. * * signer - certificate to sign bundle with * pkey - private key matching signer * certs - optional additional set of certificates to include * in - input data to be signed * flags - optional set of flags to control sign behavior * * PKCS7_BINARY - Do not translate input data to MIME canonical * format (\r\n line endings), thus preventing corruption of * binary content. * PKCS7_TEXT - Prepend MIME headers for text/plain to content. * PKCS7_DETACHED - Set signature detached, omit content from output bundle. * PKCS7_STREAM - initialize PKCS7 struct for signing, do not read data. * * Flags not currently supported: * PKCS7_NOCERTS - Do not include the signer cert in the output bundle. * PKCS7_PARTIAL - Allow for PKCS7_sign() to be only partially set up, * then signers etc to be added separately before * calling PKCS7_final(). * * Returns valid PKCS7 structure pointer, or NULL if an error occurred. */ PKCS7* wolfSSL_PKCS7_sign(WOLFSSL_X509* signer, WOLFSSL_EVP_PKEY* pkey, WOLFSSL_STACK* certs, WOLFSSL_BIO* in, int flags) { int err = 0; WOLFSSL_PKCS7* p7 = NULL; WOLFSSL_STACK* cert = certs; WOLFSSL_ENTER("wolfSSL_PKCS7_sign"); if (flags & PKCS7_NOCERTS) { WOLFSSL_MSG("PKCS7_NOCERTS flag not yet supported"); err = 1; } if (flags & PKCS7_PARTIAL) { WOLFSSL_MSG("PKCS7_PARTIAL flag not yet supported"); err = 1; } if ((err == 0) && (signer == NULL || signer->derCert == NULL || signer->derCert->length == 0)) { WOLFSSL_MSG("Bad function arg, signer is NULL or incomplete"); err = 1; } if ((err == 0) && (pkey == NULL || pkey->pkey.ptr == NULL || pkey->pkey_sz <= 0)) { WOLFSSL_MSG("Bad function arg, pkey is NULL or incomplete"); err = 1; } if ((err == 0) && (in == NULL) && !(flags & PKCS7_STREAM)) { WOLFSSL_MSG("input data required unless PKCS7_STREAM used"); err = 1; } if ((err == 0) && ((p7 = (WOLFSSL_PKCS7*)wolfSSL_PKCS7_new()) == NULL)) { WOLFSSL_MSG("Error allocating new WOLFSSL_PKCS7"); err = 1; } /* load signer certificate */ if (err == 0) { if (wc_PKCS7_InitWithCert(&p7->pkcs7, signer->derCert->buffer, signer->derCert->length) != 0) { WOLFSSL_MSG("Failed to load signer certificate"); err = 1; } } /* set signer private key, data types, defaults */ if (err == 0) { p7->pkcs7.privateKey = (byte*)pkey->pkey.ptr; p7->pkcs7.privateKeySz = pkey->pkey_sz; p7->pkcs7.contentOID = DATA; /* inner content default is DATA */ p7->pkcs7.hashOID = SHA256h; /* default to SHA-256 hash type */ p7->type = SIGNED_DATA; /* PKCS7_final switches on type */ } /* add additional chain certs if provided */ while (cert && (err == 0)) { if (cert->data.x509 != NULL && cert->data.x509->derCert != NULL) { if (wc_PKCS7_AddCertificate(&p7->pkcs7, cert->data.x509->derCert->buffer, cert->data.x509->derCert->length) != 0) { WOLFSSL_MSG("Error in wc_PKCS7_AddCertificate"); err = 1; } } cert = cert->next; } if ((err == 0) && (flags & PKCS7_DETACHED)) { if (wc_PKCS7_SetDetached(&p7->pkcs7, 1) != 0) { WOLFSSL_MSG("Failed to set signature detached"); err = 1; } } if ((err == 0) && (flags & PKCS7_STREAM)) { /* if streaming, return before finalizing */ return (PKCS7*)p7; } if ((err == 0) && (wolfSSL_PKCS7_final((PKCS7*)p7, in, flags) != 1)) { WOLFSSL_MSG("Error calling wolfSSL_PKCS7_final"); err = 1; } if ((err != 0) && (p7 != NULL)) { wolfSSL_PKCS7_free((PKCS7*)p7); p7 = NULL; } return (PKCS7*)p7; } #ifdef HAVE_SMIME #ifndef MAX_MIME_LINE_LEN #define MAX_MIME_LINE_LEN 1024 #endif /** * Copy input BIO to output BIO, but convert all line endings to CRLF (\r\n), * used by PKCS7_final(). * * in - input WOLFSSL_BIO to be converted * out - output WOLFSSL_BIO to hold copy of in, with line endings adjusted * * Return 0 on success, negative on error */ static int wolfSSL_BIO_to_MIME_crlf(WOLFSSL_BIO* in, WOLFSSL_BIO* out) { int ret = 0; int lineLen = 0; word32 canonLineLen = 0; char* canonLine = NULL; #ifdef WOLFSSL_SMALL_STACK char* line = NULL; #else char line[MAX_MIME_LINE_LEN]; #endif if (in == NULL || out == NULL) { return BAD_FUNC_ARG; } #ifdef WOLFSSL_SMALL_STACK line = (char*)XMALLOC(MAX_MIME_LINE_LEN, in->heap, DYNAMIC_TYPE_TMP_BUFFER); if (line == NULL) { return MEMORY_E; } #endif XMEMSET(line, 0, MAX_MIME_LINE_LEN); while ((lineLen = wolfSSL_BIO_gets(in, line, (int)sizeof(line))) > 0) { if (line[lineLen - 1] == '\r' || line[lineLen - 1] == '\n') { canonLineLen = (word32)lineLen; if ((canonLine = wc_MIME_single_canonicalize( line, &canonLineLen)) == NULL) { ret = -1; break; } /* remove trailing null */ if (canonLine[canonLineLen] == '\0') { canonLineLen--; } if (wolfSSL_BIO_write(out, canonLine, (int)canonLineLen) < 0) { ret = -1; break; } XFREE(canonLine, NULL, DYNAMIC_TYPE_PKCS7); canonLine = NULL; } else { /* no line ending in current line, write direct to out */ if (wolfSSL_BIO_write(out, line, lineLen) < 0) { ret = -1; break; } } } if (canonLine != NULL) { XFREE(canonLine, NULL, DYNAMIC_TYPE_PKCS7); } #ifdef WOLFSSL_SMALL_STACK XFREE(line, in->heap, DYNAMIC_TYPE_TMP_BUFFER); #endif return ret; } #endif /* HAVE_SMIME */ /* Used by both PKCS7_final() and PKCS7_verify() */ static const char contTypeText[] = "Content-Type: text/plain\r\n\r\n"; /** * Finalize PKCS7 structure, currently supports signedData only. * * Does not generate final bundle (ie: signedData), but finalizes * the PKCS7 structure in preparation for a output function to be called next. * * pkcs7 - initialized PKCS7 structure, populated with signer, etc * in - input data * flags - flags to control PKCS7 behavior. Other flags except those noted * below are ignored: * * PKCS7_BINARY - Do not translate input data to MIME canonical * format (\r\n line endings), thus preventing corruption of * binary content. * PKCS7_TEXT - Prepend MIME headers for text/plain to content. * * Returns 1 on success, 0 on error */ int wolfSSL_PKCS7_final(PKCS7* pkcs7, WOLFSSL_BIO* in, int flags) { int ret = 1; int memSz = 0; unsigned char* mem = NULL; WOLFSSL_PKCS7* p7 = (WOLFSSL_PKCS7*)pkcs7; WOLFSSL_BIO* data = NULL; WOLFSSL_ENTER("wolfSSL_PKCS7_final"); if (p7 == NULL || in == NULL) { WOLFSSL_MSG("Bad input args to PKCS7_final"); ret = 0; } if (ret == 1) { if ((data = wolfSSL_BIO_new(wolfSSL_BIO_s_mem())) == NULL) { WOLFSSL_MSG("Error in wolfSSL_BIO_new"); ret = 0; } } /* prepend Content-Type header if PKCS7_TEXT */ if ((ret == 1) && (flags & PKCS7_TEXT)) { if (wolfSSL_BIO_write(data, contTypeText, (int)XSTR_SIZEOF(contTypeText)) < 0) { WOLFSSL_MSG("Error prepending Content-Type header"); ret = 0; } } /* convert line endings to CRLF if !PKCS7_BINARY */ if (ret == 1) { if (flags & PKCS7_BINARY) { /* no CRLF conversion, direct copy content */ if ((memSz = wolfSSL_BIO_get_len(in)) <= 0) { ret = 0; } if (ret == 1) { mem = (unsigned char*)XMALLOC(memSz, in->heap, DYNAMIC_TYPE_TMP_BUFFER); if (mem == NULL) { WOLFSSL_MSG("Failed to allocate memory for input data"); ret = 0; } } if (ret == 1) { if (wolfSSL_BIO_read(in, mem, memSz) != memSz) { WOLFSSL_MSG("Error reading from input BIO"); ret = 0; } else if (wolfSSL_BIO_write(data, mem, memSz) < 0) { ret = 0; } } if (mem != NULL) { XFREE(mem, in->heap, DYNAMIC_TYPE_TMP_BUFFER); } } else { #ifdef HAVE_SMIME /* convert content line endings to CRLF */ if (wolfSSL_BIO_to_MIME_crlf(in, data) != 0) { WOLFSSL_MSG("Error converting line endings to CRLF"); ret = 0; } else { p7->pkcs7.contentCRLF = 1; } #else WOLFSSL_MSG("Without PKCS7_BINARY requires wolfSSL to be built " "with HAVE_SMIME"); ret = 0; #endif } } if ((ret == 1) && ((memSz = wolfSSL_BIO_get_mem_data(data, &mem)) < 0)) { WOLFSSL_MSG("Error in wolfSSL_BIO_get_mem_data"); ret = 0; } if (ret == 1) { if (p7->data != NULL) { XFREE(p7->data, NULL, DYNAMIC_TYPE_PKCS7); } p7->data = (byte*)XMALLOC(memSz, NULL, DYNAMIC_TYPE_PKCS7); if (p7->data == NULL) { ret = 0; } else { XMEMCPY(p7->data, mem, memSz); p7->len = memSz; } } if (ret == 1) { p7->pkcs7.content = p7->data; p7->pkcs7.contentSz = p7->len; } if (data != NULL) { wolfSSL_BIO_free(data); } return ret; } int wolfSSL_PKCS7_verify(PKCS7* pkcs7, WOLFSSL_STACK* certs, WOLFSSL_X509_STORE* store, WOLFSSL_BIO* in, WOLFSSL_BIO* out, int flags) { int i, ret = 0; unsigned char* mem = NULL; int memSz = 0; WOLFSSL_PKCS7* p7 = (WOLFSSL_PKCS7*)pkcs7; int contTypeLen; WOLFSSL_X509* signer = NULL; WOLFSSL_STACK* signers = NULL; WOLFSSL_ENTER("wolfSSL_PKCS7_verify"); if (pkcs7 == NULL) return WOLFSSL_FAILURE; if (in != NULL) { if ((memSz = wolfSSL_BIO_get_mem_data(in, &mem)) < 0) return WOLFSSL_FAILURE; p7->pkcs7.content = mem; p7->pkcs7.contentSz = memSz; } /* certs is the list of certificates to find the cert with issuer/serial. */ (void)certs; /* store is the certificate store to use to verify signer certificate * associated with the signers. */ (void)store; ret = wc_PKCS7_VerifySignedData(&p7->pkcs7, p7->data, p7->len); if (ret != 0) return WOLFSSL_FAILURE; if ((flags & PKCS7_NOVERIFY) != PKCS7_NOVERIFY) { /* Verify signer certificates */ if (store == NULL || store->cm == NULL) { WOLFSSL_MSG("No store or store certs, but PKCS7_NOVERIFY not set"); return WOLFSSL_FAILURE; } signers = wolfSSL_PKCS7_get0_signers(pkcs7, certs, flags); if (signers == NULL) { WOLFSSL_MSG("No signers found to verify"); return WOLFSSL_FAILURE; } for (i = 0; i < wolfSSL_sk_X509_num(signers); i++) { signer = wolfSSL_sk_X509_value(signers, i); if (wolfSSL_CertManagerVerifyBuffer(store->cm, signer->derCert->buffer, signer->derCert->length, WOLFSSL_FILETYPE_ASN1) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("Failed to verify signer certificate"); wolfSSL_sk_X509_pop_free(signers, NULL); return WOLFSSL_FAILURE; } } wolfSSL_sk_X509_pop_free(signers, NULL); } if (flags & PKCS7_TEXT) { /* strip MIME header for text/plain, otherwise error */ contTypeLen = XSTR_SIZEOF(contTypeText); if ((p7->pkcs7.contentSz < (word32)contTypeLen) || (XMEMCMP(p7->pkcs7.content, contTypeText, contTypeLen) != 0)) { WOLFSSL_MSG("Error PKCS7 Content-Type not found with PKCS7_TEXT"); return WOLFSSL_FAILURE; } p7->pkcs7.content += contTypeLen; p7->pkcs7.contentSz -= contTypeLen; } if (out != NULL) { wolfSSL_BIO_write(out, p7->pkcs7.content, p7->pkcs7.contentSz); } WOLFSSL_LEAVE("wolfSSL_PKCS7_verify", WOLFSSL_SUCCESS); return WOLFSSL_SUCCESS; } /** * This API was added as a helper function for libest. It * encodes a stack of certificates to pkcs7 format. * @param pkcs7 PKCS7 parameter object * @param certs WOLFSSL_STACK_OF(WOLFSSL_X509)* * @param out Output bio * @return WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE on failure */ int wolfSSL_PKCS7_encode_certs(PKCS7* pkcs7, WOLFSSL_STACK* certs, WOLFSSL_BIO* out) { int ret; WOLFSSL_PKCS7* p7; WOLFSSL_ENTER("wolfSSL_PKCS7_encode_certs"); if (!pkcs7 || !certs || !out) { WOLFSSL_MSG("Bad parameter"); return WOLFSSL_FAILURE; } p7 = (WOLFSSL_PKCS7*)pkcs7; /* take ownership of certs */ p7->certs = certs; if (pkcs7->certList) { WOLFSSL_MSG("wolfSSL_PKCS7_encode_certs called multiple times on same " "struct"); return WOLFSSL_FAILURE; } if (certs) { /* Save some of the values */ int hashOID = pkcs7->hashOID; byte version = pkcs7->version; if (!certs->data.x509 || !certs->data.x509->derCert) { WOLFSSL_MSG("Missing cert"); return WOLFSSL_FAILURE; } if (wc_PKCS7_InitWithCert(pkcs7, certs->data.x509->derCert->buffer, certs->data.x509->derCert->length) != 0) { WOLFSSL_MSG("wc_PKCS7_InitWithCert error"); return WOLFSSL_FAILURE; } certs = certs->next; pkcs7->hashOID = hashOID; pkcs7->version = version; } /* Add the certs to the PKCS7 struct */ while (certs) { if (!certs->data.x509 || !certs->data.x509->derCert) { WOLFSSL_MSG("Missing cert"); return WOLFSSL_FAILURE; } if (wc_PKCS7_AddCertificate(pkcs7, certs->data.x509->derCert->buffer, certs->data.x509->derCert->length) != 0) { WOLFSSL_MSG("wc_PKCS7_AddCertificate error"); return WOLFSSL_FAILURE; } certs = certs->next; } if (wc_PKCS7_SetSignerIdentifierType(pkcs7, DEGENERATE_SID) != 0) { WOLFSSL_MSG("wc_PKCS7_SetSignerIdentifierType error"); return WOLFSSL_FAILURE; } ret = wolfSSL_i2d_PKCS7_bio(out, pkcs7); return ret; } /****************************************************************************** * wolfSSL_PEM_write_bio_PKCS7 - writes the PKCS7 data to BIO * * RETURNS: * returns WOLFSSL_SUCCESS on success, otherwise returns WOLFSSL_FAILURE */ int wolfSSL_PEM_write_bio_PKCS7(WOLFSSL_BIO* bio, PKCS7* p7) { #ifdef WOLFSSL_SMALL_STACK byte* outputHead; byte* outputFoot; #else byte outputHead[2048]; byte outputFoot[2048]; #endif word32 outputHeadSz = 2048; word32 outputFootSz = 2048; word32 outputSz = 0; byte* output = NULL; byte* pem = NULL; int pemSz = -1; enum wc_HashType hashType; byte hashBuf[WC_MAX_DIGEST_SIZE]; word32 hashSz = -1; WOLFSSL_ENTER("wolfSSL_PEM_write_bio_PKCS7()"); if (bio == NULL || p7 == NULL) return WOLFSSL_FAILURE; #ifdef WOLFSSL_SMALL_STACK outputHead = (byte*)XMALLOC(outputHeadSz, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); if (outputHead == NULL) return MEMORY_E; outputFoot = (byte*)XMALLOC(outputFootSz, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); if (outputFoot == NULL) goto error; #endif XMEMSET(hashBuf, 0, WC_MAX_DIGEST_SIZE); XMEMSET(outputHead, 0, outputHeadSz); XMEMSET(outputFoot, 0, outputFootSz); hashType = wc_OidGetHash(p7->hashOID); hashSz = wc_HashGetDigestSize(hashType); if (hashSz > WC_MAX_DIGEST_SIZE) return WOLFSSL_FAILURE; /* only SIGNED_DATA is supported */ switch (p7->contentOID) { case SIGNED_DATA: break; default: WOLFSSL_MSG("Unknown PKCS#7 Type"); return WOLFSSL_FAILURE; }; if ((wc_PKCS7_EncodeSignedData_ex(p7, hashBuf, hashSz, outputHead, &outputHeadSz, outputFoot, &outputFootSz)) != 0) return WOLFSSL_FAILURE; outputSz = outputHeadSz + p7->contentSz + outputFootSz; output = (byte*)XMALLOC(outputSz, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); if (!output) return WOLFSSL_FAILURE; XMEMSET(output, 0, outputSz); outputSz = 0; XMEMCPY(&output[outputSz], outputHead, outputHeadSz); outputSz += outputHeadSz; XMEMCPY(&output[outputSz], p7->content, p7->contentSz); outputSz += p7->contentSz; XMEMCPY(&output[outputSz], outputFoot, outputFootSz); outputSz += outputFootSz; /* get PEM size */ pemSz = wc_DerToPemEx(output, outputSz, NULL, 0, NULL, CERT_TYPE); if (pemSz < 0) goto error; pemSz++; /* for '\0'*/ /* create PEM buffer and convert from DER to PEM*/ if ((pem = (byte*)XMALLOC(pemSz, bio->heap, DYNAMIC_TYPE_TMP_BUFFER)) == NULL) goto error; XMEMSET(pem, 0, pemSz); if (wc_DerToPemEx(output, outputSz, pem, pemSz, NULL, CERT_TYPE) < 0) { goto error; } if ((wolfSSL_BIO_write(bio, pem, pemSz) == pemSz)) { XFREE(output, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); XFREE(pem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); #ifdef WOLFSSL_SMALL_STACK XFREE(outputHead, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); XFREE(outputFoot, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); #endif return WOLFSSL_SUCCESS; } error: #ifdef WOLFSSL_SMALL_STACK if (outputHead) { XFREE(outputHead, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); } if (outputFoot) { XFREE(outputFoot, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); } #endif if (output) { XFREE(output, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); } if (pem) { XFREE(pem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); } return WOLFSSL_FAILURE; } #ifdef HAVE_SMIME /***************************************************************************** * wolfSSL_SMIME_read_PKCS7 - Reads the given S/MIME message and parses it into * a PKCS7 object. In case of a multipart message, stores the signed data in * bcont. * * RETURNS: * returns pointer to a PKCS7 structure on success, otherwise returns NULL */ WOLFSSL_API PKCS7* wolfSSL_SMIME_read_PKCS7(WOLFSSL_BIO* in, WOLFSSL_BIO** bcont) { MimeHdr* allHdrs = NULL; MimeHdr* curHdr = NULL; MimeParam* curParam = NULL; int inLen = 0; byte* bcontMem = NULL; int bcontMemSz = 0; int sectionLen = 0; int ret = -1; char* section = NULL; char* canonLine = NULL; char* canonSection = NULL; PKCS7* pkcs7 = NULL; word32 outLen = 0; word32 canonLineLen = 0; byte* out = NULL; byte* outHead = NULL; int canonPos = 0; int lineLen = 0; int remainLen = 0; byte isEnd = 0; size_t canonSize = 0; size_t boundLen = 0; char* boundary = NULL; static const char kContType[] = "Content-Type"; static const char kCTE[] = "Content-Transfer-Encoding"; static const char kMultSigned[] = "multipart/signed"; static const char kAppPkcsSign[] = "application/pkcs7-signature"; static const char kAppXPkcsSign[] = "application/x-pkcs7-signature"; static const char kAppPkcs7Mime[] = "application/pkcs7-mime"; static const char kAppXPkcs7Mime[] = "application/x-pkcs7-mime"; WOLFSSL_ENTER("wolfSSL_SMIME_read_PKCS7"); if (in == NULL || bcont == NULL) { goto error; } inLen = wolfSSL_BIO_get_len(in); if (inLen <= 0) { goto error; } remainLen = wolfSSL_BIO_get_len(in); if (remainLen <= 0) { goto error; } section = (char*)XMALLOC(remainLen+1, NULL, DYNAMIC_TYPE_PKCS7); if (section == NULL) { goto error; } lineLen = wolfSSL_BIO_gets(in, section, remainLen); if (lineLen <= 0) { goto error; } while (isEnd == 0 && remainLen > 0) { sectionLen += lineLen; remainLen -= lineLen; lineLen = wolfSSL_BIO_gets(in, §ion[sectionLen], remainLen); if (lineLen <= 0) { goto error; } /* Line with just newline signals end of headers. */ if ((lineLen==2 && !XSTRNCMP(§ion[sectionLen], "\r\n", 2)) || (lineLen==1 && (section[sectionLen] == '\r' || section[sectionLen] == '\n'))) { isEnd = 1; } } section[sectionLen] = '\0'; ret = wc_MIME_parse_headers(section, sectionLen, &allHdrs); if (ret < 0) { WOLFSSL_MSG("Parsing MIME headers failed."); goto error; } isEnd = 0; section[0] = '\0'; sectionLen = 0; curHdr = wc_MIME_find_header_name(kContType, allHdrs); if (curHdr && !XSTRNCMP(curHdr->body, kMultSigned, XSTR_SIZEOF(kMultSigned))) { curParam = wc_MIME_find_param_attr("protocol", curHdr->params); if (curParam && (!XSTRNCMP(curParam->value, kAppPkcsSign, XSTR_SIZEOF(kAppPkcsSign)) || !XSTRNCMP(curParam->value, kAppXPkcsSign, XSTR_SIZEOF(kAppXPkcsSign)))) { curParam = wc_MIME_find_param_attr("boundary", curHdr->params); if (curParam == NULL) { goto error; } boundLen = XSTRLEN(curParam->value) + 2; boundary = (char*)XMALLOC(boundLen+1, NULL, DYNAMIC_TYPE_PKCS7); if (boundary == NULL) { goto error; } XMEMSET(boundary, 0, (word32)(boundLen+1)); boundary[0] = boundary[1] = '-'; XSTRNCPY(&boundary[2], curParam->value, boundLen-2); /* Parse up to first boundary, ignore everything here. */ lineLen = wolfSSL_BIO_gets(in, section, remainLen); if (lineLen <= 0) { goto error; } while (XSTRNCMP(§ion[sectionLen], boundary, boundLen) && remainLen > 0) { sectionLen += lineLen; remainLen -= lineLen; lineLen = wolfSSL_BIO_gets(in, §ion[sectionLen], remainLen); if (lineLen <= 0) { goto error; } } section[0] = '\0'; sectionLen = 0; canonSize = remainLen + 1; canonSection = (char*)XMALLOC(canonSize, NULL, DYNAMIC_TYPE_PKCS7); if (canonSection == NULL) { goto error; } lineLen = wolfSSL_BIO_gets(in, section, remainLen); while (XSTRNCMP(§ion[sectionLen], boundary, boundLen) && remainLen > 0) { canonLineLen = lineLen; canonLine = wc_MIME_single_canonicalize(§ion[sectionLen], &canonLineLen); if (canonLine == NULL) { goto error; } /* If line endings were added, the initial length may be * exceeded. */ if ((canonPos + canonLineLen) >= canonSize) { canonSize = canonPos + canonLineLen; canonSection = (char*)XREALLOC(canonSection, canonSize, NULL, DYNAMIC_TYPE_PKCS7); if (canonSection == NULL) { goto error; } } XMEMCPY(&canonSection[canonPos], canonLine, (int)canonLineLen - 1); canonPos += canonLineLen - 1; XFREE(canonLine, NULL, DYNAMIC_TYPE_PKCS7); canonLine = NULL; sectionLen += lineLen; remainLen -= lineLen; lineLen = wolfSSL_BIO_gets(in, §ion[sectionLen], remainLen); if (lineLen <= 0) { goto error; } } if (canonPos > 0) { canonPos--; } /* Strip the final trailing newline. Support \r, \n or \r\n. */ if (canonSection[canonPos] == '\n') { if (canonPos > 0) { canonPos--; } } if (canonSection[canonPos] == '\r') { if (canonPos > 0) { canonPos--; } } canonSection[canonPos+1] = '\0'; *bcont = wolfSSL_BIO_new(wolfSSL_BIO_s_mem()); ret = wolfSSL_BIO_write(*bcont, canonSection, canonPos + 1); if (ret != (canonPos+1)) { goto error; } if ((bcontMemSz = wolfSSL_BIO_get_mem_data(*bcont, &bcontMem)) < 0) { goto error; } XFREE(canonSection, NULL, DYNAMIC_TYPE_PKCS7); canonSection = NULL; wc_MIME_free_hdrs(allHdrs); allHdrs = NULL; section[0] = '\0'; sectionLen = 0; lineLen = wolfSSL_BIO_gets(in, section, remainLen); if (lineLen <= 0) { goto error; } while (isEnd == 0 && remainLen > 0) { sectionLen += lineLen; remainLen -= lineLen; lineLen = wolfSSL_BIO_gets(in, §ion[sectionLen], remainLen); if (lineLen <= 0) { goto error; } /* Line with just newline signals end of headers. */ if ((lineLen==2 && !XSTRNCMP(§ion[sectionLen], "\r\n", 2)) || (lineLen==1 && (section[sectionLen] == '\r' || section[sectionLen] == '\n'))) { isEnd = 1; } } section[sectionLen] = '\0'; ret = wc_MIME_parse_headers(section, sectionLen, &allHdrs); if (ret < 0) { WOLFSSL_MSG("Parsing MIME headers failed."); goto error; } curHdr = wc_MIME_find_header_name(kContType, allHdrs); if (curHdr == NULL || (XSTRNCMP(curHdr->body, kAppPkcsSign, XSTR_SIZEOF(kAppPkcsSign)) && XSTRNCMP(curHdr->body, kAppXPkcsSign, XSTR_SIZEOF(kAppXPkcsSign)))) { WOLFSSL_MSG("S/MIME headers not found inside " "multipart message.\n"); goto error; } section[0] = '\0'; sectionLen = 0; lineLen = wolfSSL_BIO_gets(in, section, remainLen); while (XSTRNCMP(§ion[sectionLen], boundary, boundLen) && remainLen > 0) { sectionLen += lineLen; remainLen -= lineLen; lineLen = wolfSSL_BIO_gets(in, §ion[sectionLen], remainLen); if (lineLen <= 0) { goto error; } } XFREE(boundary, NULL, DYNAMIC_TYPE_PKCS7); boundary = NULL; } } else if (curHdr && (!XSTRNCMP(curHdr->body, kAppPkcs7Mime, XSTR_SIZEOF(kAppPkcs7Mime)) || !XSTRNCMP(curHdr->body, kAppXPkcs7Mime, XSTR_SIZEOF(kAppXPkcs7Mime)))) { sectionLen = wolfSSL_BIO_get_len(in); if (sectionLen <= 0) { goto error; } ret = wolfSSL_BIO_read(in, section, sectionLen); if (ret < 0 || ret != sectionLen) { WOLFSSL_MSG("Error reading input BIO."); goto error; } } else { WOLFSSL_MSG("S/MIME headers not found."); goto error; } curHdr = wc_MIME_find_header_name(kCTE, allHdrs); if (curHdr == NULL) { WOLFSSL_MSG("Content-Transfer-Encoding header not found, " "assuming base64 encoding."); } else if (XSTRNCMP(curHdr->body, "base64", XSTRLEN("base64"))) { WOLFSSL_MSG("S/MIME encodings other than base64 are not " "currently supported.\n"); goto error; } if (section == NULL || sectionLen <= 0) { goto error; } outLen = ((sectionLen*3+3)/4)+1; out = (byte*)XMALLOC(outLen*sizeof(byte), NULL, DYNAMIC_TYPE_PKCS7); outHead = out; if (outHead == NULL) { goto error; } /* Strip trailing newlines. */ while ((sectionLen > 0) && (section[sectionLen-1] == '\r' || section[sectionLen-1] == '\n')) { sectionLen--; } section[sectionLen] = '\0'; ret = Base64_Decode((const byte*)section, sectionLen, out, &outLen); if (ret < 0) { WOLFSSL_MSG("Error base64 decoding S/MIME message."); goto error; } pkcs7 = wolfSSL_d2i_PKCS7_ex(NULL, (const unsigned char**)&out, outLen, bcontMem, bcontMemSz); wc_MIME_free_hdrs(allHdrs); XFREE(outHead, NULL, DYNAMIC_TYPE_PKCS7); XFREE(section, NULL, DYNAMIC_TYPE_PKCS7); return pkcs7; error: wc_MIME_free_hdrs(allHdrs); XFREE(boundary, NULL, DYNAMIC_TYPE_PKCS7); XFREE(outHead, NULL, DYNAMIC_TYPE_PKCS7); XFREE(section, NULL, DYNAMIC_TYPE_PKCS7); if (canonSection != NULL) XFREE(canonSection, NULL, DYNAMIC_TYPE_PKCS7); if (bcont) { wolfSSL_BIO_free(*bcont); *bcont = NULL; /* reset 'bcount' pointer to NULL on failure */ } return NULL; } /* Convert hash algo OID (from Hash_Sum in asn.h) to SMIME string equivalent. * Returns hash algorithm string or "unknown" if not found */ static const char* wolfSSL_SMIME_HashOIDToString(int hashOID) { switch (hashOID) { case MD5h: return "md5"; case SHAh: return "sha1"; case SHA224h: return "sha-224"; case SHA256h: return "sha-256"; case SHA384h: return "sha-384"; case SHA512h: return "sha-512"; case SHA3_224h: return "sha3-224"; case SHA3_384h: return "sha3-384"; case SHA3_512h: return "sha3-512"; default: break; } return "unknown"; } /* Convert PKCS#7 type (from PKCS7_TYPES in pkcs7.h) to SMIME string. * RFC2633 only defines signed-data, enveloped-data, certs-only. * Returns string on success, NULL on unknown type. */ static const char* wolfSSL_SMIME_PKCS7TypeToString(int type) { switch (type) { case SIGNED_DATA: return "signed-data"; case ENVELOPED_DATA: return "enveloped-data"; default: break; } return NULL; } /** * Convert PKCS7 structure to SMIME format, adding necessary headers. * * Handles generation of PKCS7 bundle (ie: signedData). PKCS7 structure * should be set up beforehand with PKCS7_sign/final/etc. Output is always * Base64 encoded. * * out - output BIO for SMIME formatted data to be placed * pkcs7 - input PKCS7 structure, initialized and set up * in - input content to be encoded into PKCS7 * flags - flags to control behavior of PKCS7 generation * * Returns 1 on success, 0 or negative on failure */ int wolfSSL_SMIME_write_PKCS7(WOLFSSL_BIO* out, PKCS7* pkcs7, WOLFSSL_BIO* in, int flags) { int i; int ret = 1; WOLFSSL_PKCS7* p7 = (WOLFSSL_PKCS7*)pkcs7; byte* p7out = NULL; int len = 0; char boundary[33]; /* 32 chars + \0 */ byte* sigBase64 = NULL; word32 sigBase64Len = 0; const char* p7TypeString = NULL; static const char alphanum[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; if (out == NULL || p7 == NULL) { WOLFSSL_MSG("Bad function arguments"); return 0; } if (in != NULL && (p7->pkcs7.content == NULL || p7->pkcs7.contentSz == 0 || p7->pkcs7.contentCRLF == 0)) { /* store and adjust content line endings for CRLF if needed */ if (wolfSSL_PKCS7_final((PKCS7*)p7, in, flags) != 1) { ret = 0; } } if (ret > 0) { /* Generate signedData bundle, DER in output (dynamic) */ if ((len = wolfSSL_i2d_PKCS7((PKCS7*)p7, &p7out)) == WOLFSSL_FAILURE) { WOLFSSL_MSG("Error in wolfSSL_i2d_PKCS7"); ret = 0; } } /* Base64 encode signedData bundle */ if (ret > 0) { if (Base64_Encode(p7out, len, NULL, &sigBase64Len) != LENGTH_ONLY_E) { ret = 0; } else { sigBase64 = (byte*)XMALLOC(sigBase64Len, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (sigBase64 == NULL) { ret = 0; } } } if (ret > 0) { XMEMSET(sigBase64, 0, sigBase64Len); if (Base64_Encode(p7out, len, sigBase64, &sigBase64Len) < 0) { WOLFSSL_MSG("Error in Base64_Encode of signature"); ret = 0; } } /* build up SMIME message */ if (ret > 0) { if (flags & PKCS7_DETACHED) { /* generate random boundary */ if (initGlobalRNG == 0 && wolfSSL_RAND_Init() != WOLFSSL_SUCCESS) { WOLFSSL_MSG("No RNG to use"); ret = 0; } /* no need to generate random byte for null terminator (size-1) */ if ((ret > 0) && (wc_RNG_GenerateBlock(&globalRNG, (byte*)boundary, sizeof(boundary) - 1 ) != 0)) { WOLFSSL_MSG("Error in wc_RNG_GenerateBlock"); ret = 0; } if (ret > 0) { for (i = 0; i < (int)sizeof(boundary) - 1; i++) { boundary[i] = alphanum[boundary[i] % XSTR_SIZEOF(alphanum)]; } boundary[sizeof(boundary)-1] = 0; } if (ret > 0) { /* S/MIME header beginning */ ret = wolfSSL_BIO_printf(out, "MIME-Version: 1.0\n" "Content-Type: multipart/signed; " "protocol=\"application/x-pkcs7-signature\"; " "micalg=\"%s\"; " "boundary=\"----%s\"\n\n" "This is an S/MIME signed message\n\n" "------%s\n", wolfSSL_SMIME_HashOIDToString(p7->pkcs7.hashOID), boundary, boundary); } if (ret > 0) { /* S/MIME content */ ret = wolfSSL_BIO_write(out, p7->pkcs7.content, p7->pkcs7.contentSz); } if (ret > 0) { /* S/SMIME header end boundary */ ret = wolfSSL_BIO_printf(out, "\n------%s\n", boundary); } if (ret > 0) { /* Signature and header */ ret = wolfSSL_BIO_printf(out, "Content-Type: application/x-pkcs7-signature; " "name=\"smime.p7s\"\n" "Content-Transfer-Encoding: base64\n" "Content-Disposition: attachment; " "filename=\"smime.p7s\"\n\n" "%.*s\n" /* Base64 encoded signature */ "------%s--\n\n", sigBase64Len, sigBase64, boundary); } } else { p7TypeString = wolfSSL_SMIME_PKCS7TypeToString(p7->type); if (p7TypeString == NULL) { WOLFSSL_MSG("Unsupported PKCS7 SMIME type"); ret = 0; } if (ret > 0) { /* not detached */ ret = wolfSSL_BIO_printf(out, "MIME-Version: 1.0\n" "Content-Disposition: attachment; " "filename=\"smime.p7m\"\n" "Content-Type: application/x-pkcs7-mime; " "smime-type=%s; name=\"smime.p7m\"\n" "Content-Transfer-Encoding: base64\n\n" "%.*s\n" /* signature */, p7TypeString, sigBase64Len, sigBase64); } } } if (p7out != NULL) { XFREE(p7out, NULL, DYNAMIC_TYPE_TMP_BUFFER); } if (sigBase64 != NULL) { XFREE(sigBase64, NULL, DYNAMIC_TYPE_TMP_BUFFER); } if (ret > 0) { return WOLFSSL_SUCCESS; } return WOLFSSL_FAILURE; } #endif /* HAVE_SMIME */ #endif /* !NO_BIO */ #endif /* OPENSSL_ALL */ #endif /* HAVE_PKCS7 */ /******************************************************************************* * END OF PKCS7 APIs ******************************************************************************/ /******************************************************************************* * START OF PKCS12 APIs ******************************************************************************/ #ifdef OPENSSL_EXTRA /* no-op function. Was initially used for adding encryption algorithms available * for PKCS12 */ void wolfSSL_PKCS12_PBE_add(void) { WOLFSSL_ENTER("wolfSSL_PKCS12_PBE_add"); } #if !defined(NO_FILESYSTEM) WOLFSSL_X509_PKCS12 *wolfSSL_d2i_PKCS12_fp(XFILE fp, WOLFSSL_X509_PKCS12 **pkcs12) { WOLFSSL_ENTER("wolfSSL_d2i_PKCS12_fp"); return (WOLFSSL_X509_PKCS12 *)wolfSSL_d2i_X509_fp_ex(fp, (void **)pkcs12, PKCS12_TYPE); } #endif /* !NO_FILESYSTEM */ #endif /* OPENSSL_EXTRA */ #if defined(HAVE_PKCS12) #ifdef OPENSSL_EXTRA #if !defined(NO_ASN) && !defined(NO_PWDBASED) #ifndef NO_BIO WC_PKCS12* wolfSSL_d2i_PKCS12_bio(WOLFSSL_BIO* bio, WC_PKCS12** pkcs12) { WC_PKCS12* localPkcs12 = NULL; unsigned char* mem = NULL; long memSz; int ret = -1; WOLFSSL_ENTER("wolfSSL_d2i_PKCS12_bio"); if (bio == NULL) { WOLFSSL_MSG("Bad Function Argument bio is NULL"); return NULL; } memSz = wolfSSL_BIO_get_len(bio); if (memSz <= 0) { return NULL; } mem = (unsigned char*)XMALLOC(memSz, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); if (mem == NULL) { return NULL; } if (mem != NULL) { localPkcs12 = wc_PKCS12_new(); if (localPkcs12 == NULL) { WOLFSSL_MSG("Memory error"); } } if (mem != NULL && localPkcs12 != NULL) { if (wolfSSL_BIO_read(bio, mem, (int)memSz) == memSz) { ret = wc_d2i_PKCS12(mem, (word32)memSz, localPkcs12); if (ret < 0) { WOLFSSL_MSG("Failed to get PKCS12 sequence"); } } else { WOLFSSL_MSG("Failed to get data from bio struct"); } } /* cleanup */ if (mem != NULL) XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); if (ret < 0 && localPkcs12 != NULL) { wc_PKCS12_free(localPkcs12); localPkcs12 = NULL; } if (pkcs12 != NULL) *pkcs12 = localPkcs12; return localPkcs12; } /* Converts the PKCS12 to DER format and outputs it into bio. * * bio is the structure to hold output DER * pkcs12 structure to create DER from * * return 1 for success or 0 if an error occurs */ int wolfSSL_i2d_PKCS12_bio(WOLFSSL_BIO *bio, WC_PKCS12 *pkcs12) { int ret = WOLFSSL_FAILURE; WOLFSSL_ENTER("wolfSSL_i2d_PKCS12_bio"); if ((bio != NULL) && (pkcs12 != NULL)) { word32 certSz = 0; byte *certDer = NULL; certSz = wc_i2d_PKCS12(pkcs12, &certDer, NULL); if ((certSz > 0) && (certDer != NULL)) { if (wolfSSL_BIO_write(bio, certDer, certSz) == (int)certSz) { ret = WOLFSSL_SUCCESS; } } if (certDer != NULL) { XFREE(certDer, NULL, DYNAMIC_TYPE_PKCS); } } return ret; } #endif /* !NO_BIO */ /* Creates a new WC_PKCS12 structure * * pass password to use * name friendlyName to use * pkey private key to go into PKCS12 bundle * cert certificate to go into PKCS12 bundle * ca extra certificates that can be added to bundle. Can be NULL * keyNID type of encryption to use on the key (-1 means no encryption) * certNID type of encryption to use on the certificate * itt number of iterations with encryption * macItt number of iterations with mac creation * keyType flag for signature and/or encryption key * * returns a pointer to a new WC_PKCS12 structure on success and NULL on fail */ WC_PKCS12* wolfSSL_PKCS12_create(char* pass, char* name, WOLFSSL_EVP_PKEY* pkey, WOLFSSL_X509* cert, WOLF_STACK_OF(WOLFSSL_X509)* ca, int keyNID, int certNID, int itt, int macItt, int keyType) { WC_PKCS12* pkcs12; WC_DerCertList* list = NULL; word32 passSz; byte* keyDer = NULL; word32 keyDerSz; byte* certDer; int certDerSz; WOLFSSL_ENTER("wolfSSL_PKCS12_create()"); if (pass == NULL || pkey == NULL || cert == NULL) { WOLFSSL_LEAVE("wolfSSL_PKCS12_create()", BAD_FUNC_ARG); return NULL; } passSz = (word32)XSTRLEN(pass); keyDer = (byte*)pkey->pkey.ptr; keyDerSz = pkey->pkey_sz; certDer = (byte*)wolfSSL_X509_get_der(cert, &certDerSz); if (certDer == NULL) { return NULL; } if (ca != NULL) { WC_DerCertList* cur; unsigned long numCerts = ca->num; byte* curDer; int curDerSz = 0; WOLFSSL_STACK* sk = ca; while (numCerts > 0 && sk != NULL) { cur = (WC_DerCertList*)XMALLOC(sizeof(WC_DerCertList), NULL, DYNAMIC_TYPE_PKCS); if (cur == NULL) { wc_FreeCertList(list, NULL); return NULL; } curDer = (byte*)wolfSSL_X509_get_der(sk->data.x509, &curDerSz); if (curDer == NULL || curDerSz < 0) { XFREE(cur, NULL, DYNAMIC_TYPE_PKCS); wc_FreeCertList(list, NULL); return NULL; } cur->buffer = (byte*)XMALLOC(curDerSz, NULL, DYNAMIC_TYPE_PKCS); if (cur->buffer == NULL) { XFREE(cur, NULL, DYNAMIC_TYPE_PKCS); wc_FreeCertList(list, NULL); return NULL; } XMEMCPY(cur->buffer, curDer, curDerSz); cur->bufferSz = curDerSz; cur->next = list; list = cur; sk = sk->next; numCerts--; } } pkcs12 = wc_PKCS12_create(pass, passSz, name, keyDer, keyDerSz, certDer, certDerSz, list, keyNID, certNID, itt, macItt, keyType, NULL); if (ca != NULL) { wc_FreeCertList(list, NULL); } return pkcs12; } /* return WOLFSSL_SUCCESS on success, WOLFSSL_FAILURE on failure */ int wolfSSL_PKCS12_parse(WC_PKCS12* pkcs12, const char* psw, WOLFSSL_EVP_PKEY** pkey, WOLFSSL_X509** cert, WOLF_STACK_OF(WOLFSSL_X509)** ca) { DecodedCert DeCert; void* heap = NULL; int ret; byte* certData = NULL; word32 certDataSz; byte* pk = NULL; word32 pkSz; WC_DerCertList* certList = NULL; WOLFSSL_ENTER("wolfSSL_PKCS12_parse"); /* make sure we init return args */ if (pkey) *pkey = NULL; if (cert) *cert = NULL; if (ca) *ca = NULL; if (pkcs12 == NULL || psw == NULL || pkey == NULL || cert == NULL) { WOLFSSL_MSG("Bad argument value"); return WOLFSSL_FAILURE; } heap = wc_PKCS12_GetHeap(pkcs12); if (ca == NULL) { ret = wc_PKCS12_parse(pkcs12, psw, &pk, &pkSz, &certData, &certDataSz, NULL); } else { ret = wc_PKCS12_parse(pkcs12, psw, &pk, &pkSz, &certData, &certDataSz, &certList); } if (ret < 0) { WOLFSSL_LEAVE("wolfSSL_PKCS12_parse", ret); return WOLFSSL_FAILURE; } /* Decode cert and place in X509 stack struct */ if (certList != NULL) { WC_DerCertList* current = certList; *ca = (WOLF_STACK_OF(WOLFSSL_X509)*)XMALLOC( sizeof(WOLF_STACK_OF(WOLFSSL_X509)), heap, DYNAMIC_TYPE_X509); if (*ca == NULL) { if (pk != NULL) { XFREE(pk, heap, DYNAMIC_TYPE_PUBLIC_KEY); } if (certData != NULL) { XFREE(*cert, heap, DYNAMIC_TYPE_PKCS); *cert = NULL; } /* Free up WC_DerCertList and move on */ while (current != NULL) { WC_DerCertList* next = current->next; XFREE(current->buffer, heap, DYNAMIC_TYPE_PKCS); XFREE(current, heap, DYNAMIC_TYPE_PKCS); current = next; } return WOLFSSL_FAILURE; } XMEMSET(*ca, 0, sizeof(WOLF_STACK_OF(WOLFSSL_X509))); /* add list of DER certs as X509's to stack */ while (current != NULL) { WC_DerCertList* toFree = current; WOLFSSL_X509* x509; x509 = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), heap, DYNAMIC_TYPE_X509); InitX509(x509, 1, heap); InitDecodedCert(&DeCert, current->buffer, current->bufferSz, heap); if (ParseCertRelative(&DeCert, CERT_TYPE, NO_VERIFY, NULL) != 0) { WOLFSSL_MSG("Issue with parsing certificate"); FreeDecodedCert(&DeCert); wolfSSL_X509_free(x509); } else { if (CopyDecodedToX509(x509, &DeCert) != 0) { WOLFSSL_MSG("Failed to copy decoded cert"); FreeDecodedCert(&DeCert); wolfSSL_X509_free(x509); wolfSSL_sk_X509_pop_free(*ca, NULL); *ca = NULL; if (pk != NULL) { XFREE(pk, heap, DYNAMIC_TYPE_PUBLIC_KEY); } if (certData != NULL) { XFREE(certData, heap, DYNAMIC_TYPE_PKCS); } /* Free up WC_DerCertList */ while (current != NULL) { WC_DerCertList* next = current->next; XFREE(current->buffer, heap, DYNAMIC_TYPE_PKCS); XFREE(current, heap, DYNAMIC_TYPE_PKCS); current = next; } return WOLFSSL_FAILURE; } FreeDecodedCert(&DeCert); if (wolfSSL_sk_X509_push(*ca, x509) != 1) { WOLFSSL_MSG("Failed to push x509 onto stack"); wolfSSL_X509_free(x509); wolfSSL_sk_X509_pop_free(*ca, NULL); *ca = NULL; if (pk != NULL) { XFREE(pk, heap, DYNAMIC_TYPE_PUBLIC_KEY); } if (certData != NULL) { XFREE(certData, heap, DYNAMIC_TYPE_PKCS); } /* Free up WC_DerCertList */ while (current != NULL) { WC_DerCertList* next = current->next; XFREE(current->buffer, heap, DYNAMIC_TYPE_PKCS); XFREE(current, heap, DYNAMIC_TYPE_PKCS); current = next; } return WOLFSSL_FAILURE; } } current = current->next; XFREE(toFree->buffer, heap, DYNAMIC_TYPE_PKCS); XFREE(toFree, heap, DYNAMIC_TYPE_PKCS); } } /* Decode cert and place in X509 struct */ if (certData != NULL) { *cert = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), heap, DYNAMIC_TYPE_X509); if (*cert == NULL) { if (pk != NULL) { XFREE(pk, heap, DYNAMIC_TYPE_PUBLIC_KEY); } if (ca != NULL) { wolfSSL_sk_X509_pop_free(*ca, NULL); *ca = NULL; } XFREE(certData, heap, DYNAMIC_TYPE_PKCS); return WOLFSSL_FAILURE; } InitX509(*cert, 1, heap); InitDecodedCert(&DeCert, certData, certDataSz, heap); if (ParseCertRelative(&DeCert, CERT_TYPE, NO_VERIFY, NULL) != 0) { WOLFSSL_MSG("Issue with parsing certificate"); } if (CopyDecodedToX509(*cert, &DeCert) != 0) { WOLFSSL_MSG("Failed to copy decoded cert"); FreeDecodedCert(&DeCert); if (pk != NULL) { XFREE(pk, heap, DYNAMIC_TYPE_PUBLIC_KEY); } if (ca != NULL) { wolfSSL_sk_X509_pop_free(*ca, NULL); *ca = NULL; } wolfSSL_X509_free(*cert); *cert = NULL; return WOLFSSL_FAILURE; } FreeDecodedCert(&DeCert); XFREE(certData, heap, DYNAMIC_TYPE_PKCS); } /* get key type */ ret = BAD_STATE_E; if (pk != NULL) { /* decode key if present */ *pkey = wolfSSL_EVP_PKEY_new_ex(heap); if (*pkey == NULL) { wolfSSL_X509_free(*cert); *cert = NULL; if (ca != NULL) { wolfSSL_sk_X509_pop_free(*ca, NULL); *ca = NULL; } XFREE(pk, heap, DYNAMIC_TYPE_PUBLIC_KEY); return WOLFSSL_FAILURE; } #ifndef NO_RSA { const unsigned char* pt = pk; if (wolfSSL_d2i_PrivateKey(EVP_PKEY_RSA, pkey, &pt, pkSz) != NULL) { ret = 0; } } #endif /* NO_RSA */ #ifdef HAVE_ECC if (ret != 0) { /* if is in fail state check if ECC key */ const unsigned char* pt = pk; if (wolfSSL_d2i_PrivateKey(EVP_PKEY_EC, pkey, &pt, pkSz) != NULL) { ret = 0; } } #endif /* HAVE_ECC */ if (pk != NULL) XFREE(pk, heap, DYNAMIC_TYPE_PKCS); if (ret != 0) { /* if is in fail state and no PKEY then fail */ wolfSSL_X509_free(*cert); *cert = NULL; if (ca != NULL) { wolfSSL_sk_X509_pop_free(*ca, NULL); *ca = NULL; } wolfSSL_EVP_PKEY_free(*pkey); *pkey = NULL; WOLFSSL_MSG("Bad PKCS12 key format"); return WOLFSSL_FAILURE; } if (pkey != NULL && *pkey != NULL) { (*pkey)->save_type = 0; } } (void)ret; (void)ca; return WOLFSSL_SUCCESS; } int wolfSSL_PKCS12_verify_mac(WC_PKCS12 *pkcs12, const char *psw, int pswLen) { WOLFSSL_ENTER("wolfSSL_PKCS12_verify_mac"); if (!pkcs12) { return WOLFSSL_FAILURE; } return wc_PKCS12_verify_ex(pkcs12, (const byte*)psw, pswLen) == 0 ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; } #endif /* !NO_ASN && !NO_PWDBASED */ #endif /* OPENSSL_EXTRA */ #endif /* HAVE_PKCS12 */ /******************************************************************************* * END OF PKCS12 APIs ******************************************************************************/ #endif /* !NO_CERTS */ /******************************************************************************* * BEGIN OPENSSL FIPS DRBG APIs ******************************************************************************/ #if defined(OPENSSL_EXTRA) && !defined(WC_NO_RNG) && defined(HAVE_HASHDRBG) int wolfSSL_FIPS_drbg_init(WOLFSSL_DRBG_CTX *ctx, int type, unsigned int flags) { int ret = WOLFSSL_FAILURE; if (ctx != NULL) { XMEMSET(ctx, 0, sizeof(WOLFSSL_DRBG_CTX)); ctx->type = type; ctx->xflags = flags; ctx->status = DRBG_STATUS_UNINITIALISED; ret = WOLFSSL_SUCCESS; } return ret; } WOLFSSL_DRBG_CTX* wolfSSL_FIPS_drbg_new(int type, unsigned int flags) { int ret = WOLFSSL_FAILURE; WOLFSSL_DRBG_CTX* ctx = (WOLFSSL_DRBG_CTX*)XMALLOC(sizeof(WOLFSSL_DRBG_CTX), NULL, DYNAMIC_TYPE_OPENSSL); ret = wolfSSL_FIPS_drbg_init(ctx, type, flags); if (ret == WOLFSSL_SUCCESS && type != 0) { ret = wolfSSL_FIPS_drbg_instantiate(ctx, NULL, 0); } if (ret != WOLFSSL_SUCCESS) { WOLFSSL_ERROR(ret); wolfSSL_FIPS_drbg_free(ctx); ctx = NULL; } return ctx; } int wolfSSL_FIPS_drbg_instantiate(WOLFSSL_DRBG_CTX* ctx, const unsigned char* pers, size_t perslen) { int ret = WOLFSSL_FAILURE; if (ctx != NULL && ctx->rng == NULL) { #if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || \ (defined(HAVE_FIPS) && FIPS_VERSION_GE(5,0))) ctx->rng = wc_rng_new((byte*)pers, (word32)perslen, NULL); #else ctx->rng = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG); if (ctx->rng != NULL) { #if defined(HAVE_FIPS) && FIPS_VERSION_GE(2,0) ret = wc_InitRngNonce(ctx->rng, (byte*)pers, (word32)perslen); #else ret = wc_InitRng(ctx->rng); (void)pers; (void)perslen; #endif if (ret != 0) { WOLFSSL_ERROR(ret); XFREE(ctx->rng, NULL, DYNAMIC_TYPE_RNG); ctx->rng = NULL; } } #endif } if (ctx != NULL && ctx->rng != NULL) { ctx->status = DRBG_STATUS_READY; ret = WOLFSSL_SUCCESS; } return ret; } int wolfSSL_FIPS_drbg_set_callbacks(WOLFSSL_DRBG_CTX* ctx, drbg_entropy_get entropy_get, drbg_entropy_clean entropy_clean, size_t entropy_blocklen, drbg_nonce_get none_get, drbg_nonce_clean nonce_clean) { int ret = WOLFSSL_FAILURE; if (ctx != NULL) { ctx->entropy_get = entropy_get; ctx->entropy_clean = entropy_clean; ctx->entropy_blocklen = entropy_blocklen; ctx->none_get = none_get; ctx->nonce_clean = nonce_clean; ret = WOLFSSL_SUCCESS; } return ret; } void wolfSSL_FIPS_rand_add(const void* buf, int num, double entropy) { /* not implemented */ (void)buf; (void)num; (void)entropy; } int wolfSSL_FIPS_drbg_reseed(WOLFSSL_DRBG_CTX* ctx, const unsigned char* adin, size_t adinlen) { int ret = WOLFSSL_FAILURE; if (ctx != NULL && ctx->rng != NULL) { #if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || \ (defined(HAVE_FIPS) && FIPS_VERSION_GE(2,0))) if (wc_RNG_DRBG_Reseed(ctx->rng, adin, (word32)adinlen) == 0) { ret = WOLFSSL_SUCCESS; } #else ret = WOLFSSL_SUCCESS; (void)adin; (void)adinlen; #endif } return ret; } int wolfSSL_FIPS_drbg_generate(WOLFSSL_DRBG_CTX* ctx, unsigned char* out, size_t outlen, int prediction_resistance, const unsigned char* adin, size_t adinlen) { int ret = WOLFSSL_FAILURE; if (ctx != NULL && ctx->rng != NULL) { ret = wc_RNG_GenerateBlock(ctx->rng, out, (word32)outlen); if (ret == 0) { ret = WOLFSSL_SUCCESS; } } (void)prediction_resistance; (void)adin; (void)adinlen; return ret; } int wolfSSL_FIPS_drbg_uninstantiate(WOLFSSL_DRBG_CTX *ctx) { if (ctx != NULL && ctx->rng != NULL) { #if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || \ (defined(HAVE_FIPS) && FIPS_VERSION_GE(5,0))) wc_rng_free(ctx->rng); #else wc_FreeRng(ctx->rng); XFREE(ctx->rng, NULL, DYNAMIC_TYPE_RNG); #endif ctx->rng = NULL; ctx->status = DRBG_STATUS_UNINITIALISED; } return WOLFSSL_SUCCESS; } void wolfSSL_FIPS_drbg_free(WOLFSSL_DRBG_CTX *ctx) { if (ctx != NULL) { /* As saftey check if free'ing the default drbg, then mark global NULL. * Technically the user should not call free on the default drbg. */ if (ctx == gDrbgDefCtx) { gDrbgDefCtx = NULL; } wolfSSL_FIPS_drbg_uninstantiate(ctx); XFREE(ctx, NULL, DYNAMIC_TYPE_OPENSSL); } } WOLFSSL_DRBG_CTX* wolfSSL_FIPS_get_default_drbg(void) { if (gDrbgDefCtx == NULL) { gDrbgDefCtx = wolfSSL_FIPS_drbg_new(0, 0); } return gDrbgDefCtx; } void wolfSSL_FIPS_get_timevec(unsigned char* buf, unsigned long* pctr) { /* not implemented */ (void)buf; (void)pctr; } void* wolfSSL_FIPS_drbg_get_app_data(WOLFSSL_DRBG_CTX *ctx) { if (ctx != NULL) { return ctx->app_data; } return NULL; } void wolfSSL_FIPS_drbg_set_app_data(WOLFSSL_DRBG_CTX *ctx, void *app_data) { if (ctx != NULL) { ctx->app_data = app_data; } } #endif /******************************************************************************* * END OF OPENSSL FIPS DRBG APIs ******************************************************************************/ #endif /* !WOLFCRYPT_ONLY */ /******************************************************************************* * START OF CRYPTO-ONLY APIs ******************************************************************************/ #if defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY) || \ defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(HAVE_STUNNEL) || \ defined(WOLFSSL_NGINX) || defined(HAVE_POCO_LIB) || \ defined(WOLFSSL_HAPROXY) #ifndef NO_SHA /* One shot SHA1 hash of message. * * d message to hash * n size of d buffer * md buffer to hold digest. Should be SHA_DIGEST_SIZE. * * Note: if md is null then a static buffer of SHA_DIGEST_SIZE is used. * When the static buffer is used this function is not thread safe. * * Returns a pointer to the message digest on success and NULL on failure. */ unsigned char *wolfSSL_SHA1(const unsigned char *d, size_t n, unsigned char *md) { static byte dig[WC_SHA_DIGEST_SIZE]; byte* ret = md; wc_Sha sha; WOLFSSL_ENTER("wolfSSL_SHA1"); if (wc_InitSha_ex(&sha, NULL, INVALID_DEVID) != 0) { WOLFSSL_MSG("SHA1 Init failed"); return NULL; } if (wc_ShaUpdate(&sha, (const byte*)d, (word32)n) != 0) { WOLFSSL_MSG("SHA1 Update failed"); return NULL; } if (md == NULL) { WOLFSSL_MSG("STATIC BUFFER BEING USED. wolfSSL_SHA1 IS NOT " "THREAD SAFE WHEN md == NULL"); ret = dig; } if (wc_ShaFinal(&sha, ret) != 0) { WOLFSSL_MSG("SHA1 Final failed"); wc_ShaFree(&sha); return NULL; } wc_ShaFree(&sha); return ret; } #endif /* ! NO_SHA */ #ifdef WOLFSSL_SHA224 /* One shot SHA224 hash of message. * * d message to hash * n size of d buffer * md buffer to hold digest. Should be WC_SHA224_DIGEST_SIZE. * * Note: if md is null then a static buffer of WC_SHA256_DIGEST_SIZE is used. * When the static buffer is used this function is not thread safe. * * Returns a pointer to the message digest on success and NULL on failure. */ unsigned char *wolfSSL_SHA224(const unsigned char *d, size_t n, unsigned char *md) { static byte dig[WC_SHA224_DIGEST_SIZE]; byte* ret = md; wc_Sha256 sha; WOLFSSL_ENTER("wolfSSL_SHA224"); if (wc_InitSha224_ex(&sha, NULL, INVALID_DEVID) != 0) { WOLFSSL_MSG("SHA224 Init failed"); return NULL; } if (wc_Sha224Update(&sha, (const byte*)d, (word32)n) != 0) { WOLFSSL_MSG("SHA224 Update failed"); return NULL; } if (md == NULL) { WOLFSSL_MSG("STATIC BUFFER BEING USED. wolfSSL_SHA224 IS NOT " "THREAD SAFE WHEN md == NULL"); ret = dig; } if (wc_Sha224Final(&sha, ret) != 0) { WOLFSSL_MSG("SHA224 Final failed"); wc_Sha224Free(&sha); return NULL; } wc_Sha224Free(&sha); return ret; } #endif #ifndef NO_SHA256 /* One shot SHA256 hash of message. * * d message to hash * n size of d buffer * md buffer to hold digest. Should be WC_SHA256_DIGEST_SIZE. * * Note: if md is null then a static buffer of WC_SHA256_DIGEST_SIZE is used. * When the static buffer is used this function is not thread safe. * * Returns a pointer to the message digest on success and NULL on failure. */ unsigned char *wolfSSL_SHA256(const unsigned char *d, size_t n, unsigned char *md) { static byte dig[WC_SHA256_DIGEST_SIZE]; byte* ret = md; wc_Sha256 sha; WOLFSSL_ENTER("wolfSSL_SHA256"); if (wc_InitSha256_ex(&sha, NULL, INVALID_DEVID) != 0) { WOLFSSL_MSG("SHA256 Init failed"); return NULL; } if (wc_Sha256Update(&sha, (const byte*)d, (word32)n) != 0) { WOLFSSL_MSG("SHA256 Update failed"); return NULL; } if (md == NULL) { WOLFSSL_MSG("STATIC BUFFER BEING USED. wolfSSL_SHA256 IS NOT " "THREAD SAFE WHEN md == NULL"); ret = dig; } if (wc_Sha256Final(&sha, ret) != 0) { WOLFSSL_MSG("SHA256 Final failed"); wc_Sha256Free(&sha); return NULL; } wc_Sha256Free(&sha); return ret; } #endif /* ! NO_SHA256 */ #ifdef WOLFSSL_SHA384 /* One shot SHA384 hash of message. * * d message to hash * n size of d buffer * md buffer to hold digest. Should be WC_SHA256_DIGEST_SIZE. * * Note: if md is null then a static buffer of WC_SHA256_DIGEST_SIZE is used. * When the static buffer is used this function is not thread safe. * * Returns a pointer to the message digest on success and NULL on failure. */ unsigned char *wolfSSL_SHA384(const unsigned char *d, size_t n, unsigned char *md) { static byte dig[WC_SHA384_DIGEST_SIZE]; byte* ret = md; wc_Sha384 sha; WOLFSSL_ENTER("wolfSSL_SHA384"); if (wc_InitSha384_ex(&sha, NULL, INVALID_DEVID) != 0) { WOLFSSL_MSG("SHA384 Init failed"); return NULL; } if (wc_Sha384Update(&sha, (const byte*)d, (word32)n) != 0) { WOLFSSL_MSG("SHA384 Update failed"); return NULL; } if (md == NULL) { WOLFSSL_MSG("STATIC BUFFER BEING USED. wolfSSL_SHA384 IS NOT " "THREAD SAFE WHEN md == NULL"); ret = dig; } if (wc_Sha384Final(&sha, ret) != 0) { WOLFSSL_MSG("SHA384 Final failed"); wc_Sha384Free(&sha); return NULL; } wc_Sha384Free(&sha); return ret; } #endif /* WOLFSSL_SHA384 */ #if defined(WOLFSSL_SHA512) /* One shot SHA512 hash of message. * * d message to hash * n size of d buffer * md buffer to hold digest. Should be WC_SHA256_DIGEST_SIZE. * * Note: if md is null then a static buffer of WC_SHA256_DIGEST_SIZE is used. * When the static buffer is used this function is not thread safe. * * Returns a pointer to the message digest on success and NULL on failure. */ unsigned char *wolfSSL_SHA512(const unsigned char *d, size_t n, unsigned char *md) { static byte dig[WC_SHA512_DIGEST_SIZE]; byte* ret = md; wc_Sha512 sha; WOLFSSL_ENTER("wolfSSL_SHA512"); if (wc_InitSha512_ex(&sha, NULL, INVALID_DEVID) != 0) { WOLFSSL_MSG("SHA512 Init failed"); return NULL; } if (wc_Sha512Update(&sha, (const byte*)d, (word32)n) != 0) { WOLFSSL_MSG("SHA512 Update failed"); return NULL; } if (md == NULL) { WOLFSSL_MSG("STATIC BUFFER BEING USED. wolfSSL_SHA512 IS NOT " "THREAD SAFE WHEN md == NULL"); ret = dig; } if (wc_Sha512Final(&sha, ret) != 0) { WOLFSSL_MSG("SHA512 Final failed"); wc_Sha512Free(&sha); return NULL; } wc_Sha512Free(&sha); return ret; } #endif /* WOLFSSL_SHA512 */ #endif /* OPENSSL_EXTRA || HAVE_LIGHTY || WOLFSSL_MYSQL_COMPATIBLE || * HAVE_STUNNEL || WOLFSSL_NGINX || HAVE_POCO_LIB || WOLFSSL_HAPROXY */ /******************************************************************************* * END OF CRYPTO-ONLY APIs ******************************************************************************/