diff --git a/cyassl/error-ssl.h b/cyassl/error-ssl.h index 7b7befcbd..e0dae860d 100644 --- a/cyassl/error-ssl.h +++ b/cyassl/error-ssl.h @@ -122,6 +122,7 @@ enum CyaSSL_ErrorCodes { SESSION_TICKET_LEN_E = -389, /* Session Ticket too large */ SESSION_TICKET_EXPECT_E = -390, /* Session Ticket missing */ SCR_DIFFERENT_CERT_E = -391, /* SCR Different cert error */ + SESSION_SECRET_CB_E = -392, /* Session secret Cb fcn failure */ /* add strings to SetErrorString !!!!! */ diff --git a/cyassl/internal.h b/cyassl/internal.h index 824f743bb..d909ec109 100644 --- a/cyassl/internal.h +++ b/cyassl/internal.h @@ -2098,6 +2098,10 @@ struct CYASSL { void* RsaDecCtx; /* Rsa Private Decrypt Callback Context */ #endif /* NO_RSA */ #endif /* HAVE_PK_CALLBACKS */ +#ifdef HAVE_SECRET_CALLBACK + SessionSecretCb sessionSecretCb; + void* sessionSecretCtx; +#endif /* HAVE_SECRET_CALLBACK */ }; diff --git a/cyassl/ssl.h b/cyassl/ssl.h index 42af57e25..40ae6869c 100644 --- a/cyassl/ssl.h +++ b/cyassl/ssl.h @@ -286,6 +286,12 @@ CYASSL_API void CyaSSL_load_error_strings(void); CYASSL_API int CyaSSL_library_init(void); CYASSL_API long CyaSSL_CTX_set_session_cache_mode(CYASSL_CTX*, long); +#ifdef HAVE_SECRET_CALLBACK +typedef int (*SessionSecretCb)(CYASSL* ssl, + void* secret, int* secretSz, void* ctx); +CYASSL_API int CyaSSL_set_session_secret_cb(CYASSL*, SessionSecretCb, void*); +#endif /* HAVE_SECRET_CALLBACK */ + /* session cache persistence */ CYASSL_API int CyaSSL_save_session_cache(const char*); CYASSL_API int CyaSSL_restore_session_cache(const char*); diff --git a/src/internal.c b/src/internal.c index 9b408b1ad..a73f51de0 100644 --- a/src/internal.c +++ b/src/internal.c @@ -1899,6 +1899,10 @@ int InitSSL(CYASSL* ssl, CYASSL_CTX* ctx) ecc_init(ssl->eccDsaKey); ecc_init(ssl->eccTempKey); #endif +#ifdef HAVE_SECRET_CALLBACK + ssl->sessionSecretCb = NULL; + ssl->sessionSecretCtx = NULL; +#endif /* make sure server has DH parms, and add PSK if there, add NTRU too */ if (ssl->options.side == CYASSL_SERVER_END) @@ -7851,6 +7855,9 @@ const char* CyaSSL_ERR_reason_error_string(unsigned long e) case SCR_DIFFERENT_CERT_E: return "Peer sent different cert during SCR"; + case SESSION_SECRET_CB_E: + return "Session Secret Callback Error"; + default : return "unknown error number"; } @@ -9140,16 +9147,22 @@ static void PickHashSigAlgo(CYASSL* ssl, static INLINE int DSH_CheckSessionId(CYASSL* ssl) { - int ret; + int ret = 0; - #ifndef HAVE_SESSION_TICKET - ret = (ssl->options.haveSessionId && XMEMCMP(ssl->arrays->sessionID, +#ifdef HAVE_SECRET_CALLBACK + /* If a session secret callback exists, we are using that + * key instead of the saved session key. */ + ret = ret || (ssl->sessionSecretCb != NULL); +#endif + +#ifdef HAVE_SESSION_TICKET + ret = ret || + (!ssl->expect_session_ticket && ssl->session.ticketLen > 0); +#endif + + ret = ret || + (ssl->options.haveSessionId && XMEMCMP(ssl->arrays->sessionID, ssl->session.sessionID, ID_LEN) == 0); - #else - ret = (!ssl->expect_session_ticket && ssl->session.ticketLen > 0) || - (ssl->options.haveSessionId && XMEMCMP(ssl->arrays->sessionID, - ssl->session.sessionID, ID_LEN) == 0); - #endif return ret; } @@ -9303,6 +9316,16 @@ static void PickHashSigAlgo(CYASSL* ssl, *inOutIdx += ssl->keys.padSz; } +#ifdef HAVE_SECRET_CALLBACK + if (ssl->sessionSecretCb != NULL) { + int secretSz = SECRET_LEN, ret; + ret = ssl->sessionSecretCb(ssl, ssl->session.masterSecret, + &secretSz, ssl->sessionSecretCtx); + if (ret != 0 || secretSz != SECRET_LEN) + return SESSION_SECRET_CB_E; + } +#endif /* HAVE_SECRET_CALLBACK */ + if (ssl->options.resuming) { if (DSH_CheckSessionId(ssl)) { if (SetCipherSpecs(ssl) == 0) { diff --git a/src/ssl.c b/src/ssl.c index 10b595af5..89fe952d1 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -4310,6 +4310,26 @@ int CyaSSL_library_init(void) } +#ifdef HAVE_SECRET_CALLBACK + +int CyaSSL_set_session_secret_cb(CYASSL* ssl, SessionSecretCb cb, void* ctx) +{ + CYASSL_ENTER("CyaSSL_set_session_secret_cb"); + if (ssl == NULL) + return SSL_FATAL_ERROR; + + ssl->sessionSecretCb = cb; + ssl->sessionSecretCtx = ctx; + /* If using a pre-set key, assume session resumption. */ + ssl->session.sessionIDSz = 0; + ssl->options.resuming = 1; + + return SSL_SUCCESS; +} + +#endif + + #ifndef NO_SESSION_CACHE /* on by default if built in but allow user to turn off */