diff --git a/src/internal.c b/src/internal.c index 5d6a8fe3a..45b5dadb6 100644 --- a/src/internal.c +++ b/src/internal.c @@ -20535,6 +20535,61 @@ const char* GetCipherNameInternal(const byte cipherSuite0, const byte cipherSuit } #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) +/* Segment cipher name into n[n0,n1,n2,n4] + * @param cipher a pointer to WOLFSSL_CIPHER + * @param n return segment cipher name + * return cipher name if cipher is in the list, + * otherwise NULL + */ +const char* GetCipherSegment(const WOLFSSL_CIPHER* cipher, char n[][MAX_SEGMENT_SZ]) +{ + int i,j,k; + int strLen; + unsigned long offset; + const char* name; + + /* sanity check */ + if (cipher == NULL) + return NULL; + + offset = cipher->offset; + + if (offset >= (unsigned long)GetCipherNamesSize()) + return WOLFSSL_FAILURE; + + name = cipher_names[offset].name; + + if (name == NULL) + return NULL; + + /* Segment cipher name into n[n0,n1,n2,n4] + * These are used later for comparisons to create: + * keaStr, authStr, encStr, macStr + * + * If cipher_name = ECDHE-ECDSA-AES256-SHA + * then n0 = "ECDHE", n1 = "ECDSA", n2 = "AES256", n3 = "SHA" + * and n = [n0,n1,n2,n3,0] + */ + strLen = (int)XSTRLEN(name); + + for (i = 0, j = 0, k = 0; i <= strLen; i++) { + if (k >= MAX_SEGMENTS || j >= MAX_SEGMENT_SZ) + break; + + if (name[i] != '-' && name[i] != '\0') { + n[k][j] = name[i]; /* Fill kth segment string until '-' */ + j++; + } + else { + n[k][j] = '\0'; + j = 0; + k++; + } + } + + return name; +} + const char* GetCipherKeaStr(char n[][MAX_SEGMENT_SZ]) { const char* keaStr = NULL; const char *n0,*n1,*n2,*n3,*n4; @@ -20679,7 +20734,27 @@ const char* GetCipherEncStr(char n[][MAX_SEGMENT_SZ]) { return encStr; } - +/* Check if a cipher is AEAD + * @param n return segment cipher name + * return 1 if the cipher is AEAD, otherwise 0 + */ +int IsAEAD(char n[][MAX_SEGMENT_SZ]) +{ + const char *n1,*n2,*n3; + n1 = n[1]; + n2 = n[2]; + n3 = n[3]; + + printf("n1 %s n2 %s n3 %s\n", n1, n2, n3); + + if ((XSTRNCMP(n2,"GCM",3) == 0) || (XSTRNCMP(n3,"GCM",3) == 0) || + (XSTRNCMP(n1,"CCM",3) == 0) || + (XSTRNCMP(n2,"CCM",3) == 0) || (XSTRNCMP(n3,"CCM",3) == 0) || + (XSTRNCMP(n1,"CHACHA20",8) == 0 && XSTRNCMP(n2,"POLY1305",8) == 0) || + (XSTRNCMP(n2,"CHACHA20",8) == 0 && XSTRNCMP(n3,"POLY1305",8) == 0)) + return 1; + return 0; +} /* Returns the MAC string of a cipher or "unknown" on failure */ const char* GetCipherMacStr(char n[][MAX_SEGMENT_SZ]) { diff --git a/src/ssl.c b/src/ssl.c index 5cb2ff162..41231a58a 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -23360,6 +23360,197 @@ int wolfSSL_X509_cmp(const WOLFSSL_X509 *a, const WOLFSSL_X509 *b) #ifdef OPENSSL_EXTRA #if defined(OPENSSL_ALL) || defined(WOLFSSL_QT) +/* return authentication NID corresponding to cipher sutie + * @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* name; + const char* authStr; + char n[MAX_SEGMENTS][MAX_SEGMENT_SZ] = {{0}}; + (void)name; + + name = GetCipherSegment(cipher, n); + authStr = GetCipherAuthStr(n); + + if (authStr != NULL) { + for(sa = authnid_tbl; sa->alg_name != NULL; sa++) { + if (XSTRNCMP(sa->alg_name, authStr, XSTRLEN(sa->alg_name)) == 0) { + return sa->nid; + } + } + } + + return NID_undef; +} +/* return cipher NID corresponding to cipher sutie + * @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}, + {"IDEA", NID_idea_cbc}, + {"RABBIT", NID_undef}, + {"HC128", NID_undef}, + {NULL, NID_undef} + }; + + const struct ciphernid* c; + const char* name; + const char* encStr; + char n[MAX_SEGMENTS][MAX_SEGMENT_SZ] = {{0}}; + (void)name; + + WOLFSSL_ENTER("wolfSSL_CIPHER_get_cipher_nid"); + + name = GetCipherSegment(cipher, n); + encStr = GetCipherEncStr(n); + + if (encStr != NULL) { + for(c = ciphernid_tbl; c->alg_name != NULL; c++) { + if (XSTRNCMP(c->alg_name, encStr, XSTRLEN(c->alg_name)) == 0) { + return c->nid; + } + } + } + + return NID_undef; +} +/* return digest NID corresponding to cipher sutie + * @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"); + + name = GetCipherSegment(cipher, n); + /* 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 (XSTRNCMP(mc->alg_name, macStr, XSTRLEN(mc->alg_name)) == 0) { + return mc->nid; + } + } + } + + return NID_undef; +} +/* return key exchange NID corresponding to cipher sutie + * @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* name; + const char* keaStr; + char n[MAX_SEGMENTS][MAX_SEGMENT_SZ] = {{0}}; + (void)name; + + WOLFSSL_ENTER("wolfSSL_CIPHER_get_kx_nid"); + + name = GetCipherSegment(cipher, n); + + /* in TLS 1.3 case, NID will be NID_kx_any */ + if (XSTRNCMP(name, "TLS13", 5) == 0) { + return NID_kx_any; + } + + keaStr = GetCipherKeaStr(n); + + if (keaStr != NULL) { + for(k = kxnid_table; k->name != NULL; k++) { + if (XSTRNCMP(k->name, keaStr, XSTRLEN(k->name)) == 0) { + printf("k->name %s k->nid %d\n", k->name, k->nid); + 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) +{ + const char* name; + char n[MAX_SEGMENTS][MAX_SEGMENT_SZ] = {{0}}; + (void)name; + + WOLFSSL_ENTER("wolfSSL_CIPHER_is_aead"); + + name = GetCipherSegment(cipher, n); + return IsAEAD(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. @@ -23368,8 +23559,6 @@ int wolfSSL_X509_cmp(const WOLFSSL_X509 *a, const WOLFSSL_X509 *b) */ int wolfSSL_sk_CIPHER_description(WOLFSSL_CIPHER* cipher) { - int ret = WOLFSSL_FAILURE; - int i,j,k; int strLen; unsigned long offset; char* dp; @@ -23396,36 +23585,9 @@ int wolfSSL_sk_CIPHER_description(WOLFSSL_CIPHER* cipher) pv.major = cipher_names[offset].major; pv.minor = cipher_names[offset].minor; protocol = wolfSSL_internal_get_version(&pv); + + name = GetCipherSegment(cipher, n); - name = cipher_names[offset].name; - - if (name == NULL) - return ret; - - /* Segment cipher name into n[n0,n1,n2,n4] - * These are used later for comparisons to create: - * keaStr, authStr, encStr, macStr - * - * If cipher_name = ECDHE-ECDSA-AES256-SHA - * then n0 = "ECDHE", n1 = "ECDSA", n2 = "AES256", n3 = "SHA" - * and n = [n0,n1,n2,n3,0] - */ - strLen = (int)XSTRLEN(name); - - for (i = 0, j = 0, k = 0; i <= strLen; i++) { - if (k >= MAX_SEGMENTS || j >= MAX_SEGMENT_SZ) - break; - - if (name[i] != '-' && name[i] != '\0') { - n[k][j] = name[i]; /* Fill kth segment string until '-' */ - j++; - } - else { - n[k][j] = '\0'; - j = 0; - k++; - } - } /* keaStr */ keaStr = GetCipherKeaStr(n); /* authStr */ diff --git a/tests/api.c b/tests/api.c index 43798fa50..94b4c4f74 100644 --- a/tests/api.c +++ b/tests/api.c @@ -46715,6 +46715,143 @@ static void test_OBJ_NAME_do_all() #endif } +static void test_SSL_CIPHER_get_xxx() +{ +#if defined(OPENSSL_ALL) && !defined(NO_CERTS) && \ + !defined(NO_FILESYSTEM) + + printf(testingFmt, "test_SSL_CIPHER_get_xxx"); + + const SSL_CIPHER* cipher = NULL; + STACK_OF(SSL_CIPHER) *supportedCiphers = NULL; + int i, numCiphers = 0; + SSL_CTX* ctx; + SSL* ssl; + const char* testCertFile; + const char* testKeyFile; + char buf[256] = {0}; + + const char* cipher_id = NULL; + int expect_nid1 = NID_undef; + int expect_nid2 = NID_undef; + int expect_nid3 = NID_undef; + int expect_nid4 = NID_undef; + int expect_nid5 = 0; + + const char* cipher_id2 = NULL; + int expect_nid21 = NID_undef; + int expect_nid22 = NID_undef; + int expect_nid23 = NID_undef; + int expect_nid24 = NID_undef; + int expect_nid25 = 0; + + (void)cipher; + (void)supportedCiphers; + (void)i; + (void)numCiphers; + (void)ctx; + (void)ssl; + (void)testCertFile; + (void)testKeyFile; + +#if defined(WOLFSSL_TLS13) + cipher_id = "TLS13-AES128-GCM-SHA256"; + expect_nid1 = NID_auth_rsa; + expect_nid2 = NID_aes_128_gcm; + expect_nid3 = NID_sha256; + expect_nid4 = NID_kx_any; + expect_nid5 = 1; + + #if !defined(WOLFSSL_NO_TLS12) + cipher_id2 = "ECDHE-RSA-AES256-GCM-SHA384"; + expect_nid21 = NID_auth_rsa; + expect_nid22 = NID_aes_256_gcm; + expect_nid23 = NID_sha384; + expect_nid24 = NID_kx_ecdhe; + expect_nid25 = 1; + #endif +#endif + + #ifdef NO_WOLFSSL_SERVER + AssertNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + #else + AssertNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); + #endif + + if (cipher_id) { + #ifndef NO_RSA + testCertFile = svrCertFile; + testKeyFile = svrKeyFile; + #elif defined(HAVE_ECC) + testCertFile = eccCertFile; + testKeyFile = eccKeyFile; + #else + testCertFile = NULL; + testKeyFile = NULL; + #endif + if (testCertFile != NULL && testKeyFile != NULL) { + AssertTrue(SSL_CTX_use_certificate_file(ctx, testCertFile, + SSL_FILETYPE_PEM)); + AssertTrue(SSL_CTX_use_PrivateKey_file(ctx, testKeyFile, + SSL_FILETYPE_PEM)); + } + + ssl = SSL_new(ctx); + AssertNotNull(ssl); + AssertIntEQ(SSL_in_init(ssl), 1); + + supportedCiphers = SSL_get_ciphers(ssl); + numCiphers = sk_num(supportedCiphers); + + for (i = 0; i < numCiphers; ++i) { + + if ((cipher = (const WOLFSSL_CIPHER*)sk_value(supportedCiphers, i))) { + SSL_CIPHER_description(cipher, buf, sizeof(buf)); + } + + if (XMEMCMP(cipher_id, buf, XSTRLEN(cipher_id)) == 0) { + break; + } + } + /* test case for */ + if (i != numCiphers) { + AssertIntEQ(wolfSSL_CIPHER_get_auth_nid(cipher), expect_nid1); + AssertIntEQ(wolfSSL_CIPHER_get_cipher_nid(cipher), expect_nid2); + AssertIntEQ(wolfSSL_CIPHER_get_digest_nid(cipher), expect_nid3); + AssertIntEQ(wolfSSL_CIPHER_get_kx_nid(cipher), expect_nid4); + AssertIntEQ(wolfSSL_CIPHER_is_aead(cipher), expect_nid5); + } + + if (cipher_id2) { + + for (i = 0; i < numCiphers; ++i) { + + if ((cipher = (const WOLFSSL_CIPHER*)sk_value(supportedCiphers, i))) { + SSL_CIPHER_description(cipher, buf, sizeof(buf)); + } + + if (XMEMCMP(cipher_id2, buf, XSTRLEN(cipher_id2)) == 0) { + break; + } + } + /* test case for */ + if (i != numCiphers) { + AssertIntEQ(wolfSSL_CIPHER_get_auth_nid(cipher), expect_nid21); + AssertIntEQ(wolfSSL_CIPHER_get_cipher_nid(cipher), expect_nid22); + AssertIntEQ(wolfSSL_CIPHER_get_digest_nid(cipher), expect_nid23); + AssertIntEQ(wolfSSL_CIPHER_get_kx_nid(cipher), expect_nid24); + AssertIntEQ(wolfSSL_CIPHER_is_aead(cipher), expect_nid25); + } + } + } + + SSL_CTX_free(ctx); + SSL_free(ssl); + + printf(resultFmt, passed); +#endif +} + /*----------------------------------------------------------------------------* | Main *----------------------------------------------------------------------------*/ @@ -46735,6 +46872,7 @@ void ApiTest(void) (!defined(NO_RSA) || defined(HAVE_ECC)) test_for_double_Free(); #endif + test_SSL_CIPHER_get_xxx(); test_wolfSSL_ERR_strings(); test_wolfSSL_EVP_shake128(); test_wolfSSL_EVP_shake256(); diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 60ff15ab2..fbfe3e9f3 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -4840,12 +4840,15 @@ WOLFSSL_LOCAL const char* GetCipherNameInternal(const byte cipherSuite0, const b #define MAX_SEGMENTS 5 #define MAX_SEGMENT_SZ 20 WOLFSSL_LOCAL int wolfSSL_sk_CIPHER_description(WOLFSSL_CIPHER*); +WOLFSSL_LOCAL const char* GetCipherSegment(const WOLFSSL_CIPHER* cipher, + char n[][MAX_SEGMENT_SZ]); WOLFSSL_LOCAL const char* GetCipherProtocol(const byte minor); WOLFSSL_LOCAL const char* GetCipherKeaStr(char n[][MAX_SEGMENT_SZ]); WOLFSSL_LOCAL const char* GetCipherAuthStr(char n[][MAX_SEGMENT_SZ]); WOLFSSL_LOCAL const char* GetCipherEncStr(char n[][MAX_SEGMENT_SZ]); WOLFSSL_LOCAL const char* GetCipherMacStr(char n[][MAX_SEGMENT_SZ]); WOLFSSL_LOCAL int SetCipherBits(const char* enc); +WOLFSSL_LOCAL int IsAEAD(char n[][MAX_SEGMENT_SZ]); #endif WOLFSSL_LOCAL const char* GetCipherNameIana(const byte cipherSuite0, const byte cipherSuite); WOLFSSL_LOCAL const char* wolfSSL_get_cipher_name_internal(WOLFSSL* ssl); diff --git a/wolfssl/openssl/evp.h b/wolfssl/openssl/evp.h index 49491f417..fec7ea3f8 100644 --- a/wolfssl/openssl/evp.h +++ b/wolfssl/openssl/evp.h @@ -254,6 +254,7 @@ enum { NID_hmac = 855, NID_cmac = 894, NID_dhKeyAgreement= 28, + NID_rc4 = 5, EVP_PKEY_DH = NID_dhKeyAgreement, EVP_PKEY_HMAC = NID_hmac, AES_128_CFB1_TYPE = 24, @@ -304,6 +305,8 @@ enum { NID_aes_128_cbc = 419, NID_aes_192_cbc = 423, NID_aes_256_cbc = 427, + NID_aes_128_ccm = 896, + NID_aes_256_ccm = 902, NID_aes_128_gcm = 895, NID_aes_192_gcm = 898, NID_aes_256_gcm = 901, @@ -331,7 +334,34 @@ enum { NID_aes_192_ofb = 424, NID_aes_256_ofb = 428, NID_aes_128_xts = 913, - NID_aes_256_xts = 914 + NID_aes_256_xts = 914, + NID_camellia_128_cbc = 751, + NID_camellia_256_cbc = 753, + NID_chacha20_poly1305 = 1018 +}; + +enum { + /* key exchange */ + NID_kx_rsa = 1037, + NID_kx_ecdhe = 1038, + NID_kx_dhe = 1039, + NID_kx_ecdhe_psk= 1040, + NID_kx_dhe_psk = 1041, + NID_kx_rsa_psk= 1042, + NID_kx_psk = 1043, + NID_kx_srp = 1044, + NID_kx_gost = 1045, + NID_kx_any = 1063, + + /* server authentication */ + NID_auth_rsa = 1046, + NID_auth_ecdsa = 1047, + NID_auth_psk = 1048, + NID_auth_dss = 1049, + NID_auth_srp = 1052, + NID_auth_null = 1054, + NID_auth_any = 1055 + }; #define NID_X9_62_id_ecPublicKey EVP_PKEY_EC diff --git a/wolfssl/openssl/ssl.h b/wolfssl/openssl/ssl.h index 14843fd2b..bcda6180b 100644 --- a/wolfssl/openssl/ssl.h +++ b/wolfssl/openssl/ssl.h @@ -360,6 +360,11 @@ typedef STACK_OF(ACCESS_DESCRIPTION) AUTHORITY_INFO_ACCESS; #define SSL_CIPHER_get_id wolfSSL_CIPHER_get_id #define SSL_CIPHER_get_rfc_name wolfSSL_CIPHER_get_name #define SSL_CIPHER_standard_name wolfSSL_CIPHER_get_name +#define SSL_CIPHER_get_auth_nid wolfSSL_CIPHER_get_auth_nid +#define SSL_CIPHER_get_cipher_nid wolfSSL_CIPHER_get_cipher_nid +#define SSL_CIPHER_get_digest_nid wolfSSL_CIPHER_get_digest_nid +#define SSL_CIPHER_get_kx_nid wolfSSL_CIPHER_get_kx_nid +#define SSL_CIPHER_is_aead wolfSSL_CIPHER_is_aead #define SSL_get_cipher_by_value wolfSSL_get_cipher_by_value #define SSL_get1_session wolfSSL_get1_session diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 290737337..36b1259d4 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -1387,6 +1387,11 @@ WOLFSSL_API char* wolfSSL_CIPHER_description(const WOLFSSL_CIPHER*, char*, int); WOLFSSL_API const char* wolfSSL_CIPHER_get_name(const WOLFSSL_CIPHER* cipher); WOLFSSL_API const char* wolfSSL_CIPHER_get_version(const WOLFSSL_CIPHER* cipher); WOLFSSL_API word32 wolfSSL_CIPHER_get_id(const WOLFSSL_CIPHER* cipher); +WOLFSSL_API int wolfSSL_CIPHER_get_auth_nid(const WOLFSSL_CIPHER* cipher); +WOLFSSL_API int wolfSSL_CIPHER_get_cipher_nid(const WOLFSSL_CIPHER* cipher); +WOLFSSL_API int wolfSSL_CIPHER_get_digest_nid(const WOLFSSL_CIPHER* cipher); +WOLFSSL_API int wolfSSL_CIPHER_get_kx_nid(const WOLFSSL_CIPHER* cipher); +WOLFSSL_API int wolfSSL_CIPHER_is_aead(const WOLFSSL_CIPHER* cipher); WOLFSSL_API const WOLFSSL_CIPHER* wolfSSL_get_cipher_by_value(word16 value); WOLFSSL_API const char* wolfSSL_SESSION_CIPHER_get_name(WOLFSSL_SESSION* session); WOLFSSL_API const char* wolfSSL_get_cipher(WOLFSSL*);