diff --git a/certs/server-keyPkcs8.der b/certs/server-keyPkcs8.der new file mode 100644 index 000000000..5a5873543 Binary files /dev/null and b/certs/server-keyPkcs8.der differ diff --git a/tests/api.c b/tests/api.c index 5431d1b39..7fb55c6e1 100644 --- a/tests/api.c +++ b/tests/api.c @@ -36,6 +36,9 @@ #ifdef HAVE_ECC #include /* wc_ecc_fp_free */ #endif +#ifndef NO_ASN + #include +#endif #include #include @@ -3026,6 +3029,52 @@ static void test_wolfSSL_BIO(void) } +/*----------------------------------------------------------------------------* + | wolfCrypt ASN + *----------------------------------------------------------------------------*/ + +static void test_wc_GetPkcs8TraditionalOffset(void) +{ +#if !defined(NO_ASN) && !defined(NO_FILESYSTEM) + int length, derSz; + word32 inOutIdx; + const char* path = "./certs/server-keyPkcs8.der"; + FILE* file; + byte der[2048]; + + printf(testingFmt, "wc_GetPkcs8TraditionalOffset"); + + file = fopen(path, "rb"); + AssertNotNull(file); + derSz = (int)fread(der, 1, sizeof(der), file); + fclose(file); + + /* valid case */ + inOutIdx = 0; + length = wc_GetPkcs8TraditionalOffset(der, &inOutIdx, derSz); + AssertIntGT(length, 0); + + /* inOutIdx > sz */ + inOutIdx = 4000; + length = wc_GetPkcs8TraditionalOffset(der, &inOutIdx, derSz); + AssertIntEQ(length, BAD_FUNC_ARG); + + /* null input */ + inOutIdx = 0; + length = wc_GetPkcs8TraditionalOffset(NULL, &inOutIdx, 0); + AssertIntEQ(length, BAD_FUNC_ARG); + + /* invalid input, fill buffer with 1's */ + XMEMSET(der, 1, sizeof(der)); + inOutIdx = 0; + length = wc_GetPkcs8TraditionalOffset(der, &inOutIdx, derSz); + AssertIntEQ(length, ASN_PARSE_E); + + printf(resultFmt, passed); +#endif /* NO_ASN */ +} + + /*----------------------------------------------------------------------------* | Main *----------------------------------------------------------------------------*/ @@ -3086,6 +3135,10 @@ void ApiTest(void) test_wolfSSL_BIO(); AssertIntEQ(test_wolfSSL_Cleanup(), SSL_SUCCESS); + + /* wolfCrypt ASN tests */ + test_wc_GetPkcs8TraditionalOffset(); + printf(" End API Tests\n"); } diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index a6e5e4935..c23cf87b9 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -1520,34 +1520,58 @@ int wc_RsaPrivateKeyDecode(const byte* input, word32* inOutIdx, RsaKey* key, #endif /* HAVE_USER_RSA */ #endif /* NO_RSA */ +/* Remove PKCS8 header, place inOutIdx at beginning of traditional, + * return traditional length on success, negative on error */ +int ToTraditionalInline(const byte* input, word32* inOutIdx, word32 sz) +{ + word32 idx, oid; + int version, length; + + if (input == NULL || inOutIdx == NULL) + return BAD_FUNC_ARG; + + idx = *inOutIdx; + + if (GetSequence(input, &idx, &length, sz) < 0) + return ASN_PARSE_E; + + if (GetMyVersion(input, &idx, &version, sz) < 0) + return ASN_PARSE_E; + + if (GetAlgoId(input, &idx, &oid, oidKeyType, sz) < 0) + return ASN_PARSE_E; + + if (input[idx] == ASN_OBJECT_ID) { + /* pkcs8 ecc uses slightly different format */ + idx++; /* past id */ + if (GetLength(input, &idx, &length, sz) < 0) + return ASN_PARSE_E; + idx += length; /* over sub id, key input will verify */ + } + + if (input[idx++] != ASN_OCTET_STRING) + return ASN_PARSE_E; + + if (GetLength(input, &idx, &length, sz) < 0) + return ASN_PARSE_E; + + *inOutIdx = idx; + + return length; +} + /* Remove PKCS8 header, move beginning of traditional to beginning of input */ int ToTraditional(byte* input, word32 sz) { - word32 inOutIdx = 0, oid; - int version, length; + word32 inOutIdx = 0; + int length; - if (GetSequence(input, &inOutIdx, &length, sz) < 0) - return ASN_PARSE_E; + if (input == NULL) + return BAD_FUNC_ARG; - if (GetMyVersion(input, &inOutIdx, &version, sz) < 0) - return ASN_PARSE_E; - - if (GetAlgoId(input, &inOutIdx, &oid, oidKeyType, sz) < 0) - return ASN_PARSE_E; - - if (input[inOutIdx] == ASN_OBJECT_ID) { - /* pkcs8 ecc uses slightly different format */ - inOutIdx++; /* past id */ - if (GetLength(input, &inOutIdx, &length, sz) < 0) - return ASN_PARSE_E; - inOutIdx += length; /* over sub id, key input will verify */ - } - - if (input[inOutIdx++] != ASN_OCTET_STRING) - return ASN_PARSE_E; - - if (GetLength(input, &inOutIdx, &length, sz) < 0) - return ASN_PARSE_E; + length = ToTraditionalInline(input, &inOutIdx, sz); + if (length < 0) + return length; XMEMMOVE(input, input + inOutIdx, length); @@ -1555,6 +1579,23 @@ int ToTraditional(byte* input, word32 sz) } +/* find beginning of traditional key inside PKCS#8 unencrypted buffer + * return traditional length on success, with inOutIdx at beginning of + * traditional + * return negative on failure/error */ +int wc_GetPkcs8TraditionalOffset(byte* input, word32* inOutIdx, word32 sz) +{ + int length; + + if (input == NULL || inOutIdx == NULL || (*inOutIdx > sz)) + return BAD_FUNC_ARG; + + length = ToTraditionalInline(input, inOutIdx, sz); + + return length; +} + + /* check that the private key is a pair for the public key in certificate * return 1 (true) on match * return 0 or negative value on failure/error diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index 23930faeb..f1419a1d2 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -680,6 +680,8 @@ WOLFSSL_LOCAL void FreeTrustedPeerTable(TrustedPeerCert**, int, void*); #endif /* WOLFSSL_TRUST_PEER_CERT */ WOLFSSL_ASN_API int ToTraditional(byte* buffer, word32 length); +WOLFSSL_LOCAL int ToTraditionalInline(const byte* input, word32* inOutIdx, + word32 length); WOLFSSL_LOCAL int ToTraditionalEnc(byte* buffer, word32 length,const char*,int); WOLFSSL_LOCAL int DecryptContent(byte* input, word32 sz,const char* psw,int pswSz); diff --git a/wolfssl/wolfcrypt/asn_public.h b/wolfssl/wolfcrypt/asn_public.h index 242018ad7..78c48c684 100644 --- a/wolfssl/wolfcrypt/asn_public.h +++ b/wolfssl/wolfcrypt/asn_public.h @@ -268,6 +268,9 @@ WOLFSSL_API word32 wc_EncodeSignature(byte* out, const byte* digest, word32 digSz, int hashOID); WOLFSSL_API int wc_GetCTC_HashOID(int type); +WOLFSSL_API int wc_GetPkcs8TraditionalOffset(byte* input, + word32* inOutIdx, word32 sz); + /* Time */ /* Returns seconds (Epoch/UTC) * timePtr: is "time_t", which is typically "long"