diff --git a/certs/test/include.am b/certs/test/include.am index fef473888..d7c7e4cef 100644 --- a/certs/test/include.am +++ b/certs/test/include.am @@ -48,6 +48,7 @@ EXTRA_DIST += \ certs/test/server-localhost.der \ certs/test/server-localhost.pem \ certs/test/smime-test.p7s \ + certs/test/smime-test-canon.p7s \ certs/test/smime-test-multipart.p7s \ certs/test/smime-test-multipart-badsig.p7s \ certs/crl/server-goodaltCrl.pem \ diff --git a/certs/test/smime-test-canon.p7s b/certs/test/smime-test-canon.p7s new file mode 100644 index 000000000..d95207fb2 --- /dev/null +++ b/certs/test/smime-test-canon.p7s @@ -0,0 +1,63 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----7DB22CE8F405BFCE81603E2CD3794291" + +This is an S/MIME signed message + +------7DB22CE8F405BFCE81603E2CD3794291 +Content-Type: text/plain + +This text/plain content has been signed with canonicalized CRLF line endings, +but it is added to the multipart message with non canonicalized line endings. + +In order to match the hash, it will need to be canonicalized first. +------7DB22CE8F405BFCE81603E2CD3794291 +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIH3gYJKoZIhvcNAQcCoIIHzzCCB8sCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggTtMIIE6TCCA9GgAwIBAgIJAKrTP6wYCjdNMA0GCSqGSIb3DQEB +CwUAMIGUMQswCQYDVQQGEwJVUzEQMA4GA1UECAwHTW9udGFuYTEQMA4GA1UEBwwH +Qm96ZW1hbjERMA8GA1UECgwIU2F3dG9vdGgxEzARBgNVBAsMCkNvbnN1bHRpbmcx +GDAWBgNVBAMMD3d3dy53b2xmc3NsLmNvbTEfMB0GCSqGSIb3DQEJARYQaW5mb0B3 +b2xmc3NsLmNvbTAeFw0yMTAyMTAxOTQ5NTJaFw0yMzExMDcxOTQ5NTJaMIGUMQsw +CQYDVQQGEwJVUzEQMA4GA1UECAwHTW9udGFuYTEQMA4GA1UEBwwHQm96ZW1hbjER +MA8GA1UECgwIU2F3dG9vdGgxEzARBgNVBAsMCkNvbnN1bHRpbmcxGDAWBgNVBAMM +D3d3dy53b2xmc3NsLmNvbTEfMB0GCSqGSIb3DQEJARYQaW5mb0B3b2xmc3NsLmNv +bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL8Myi0Ush6EQlvNOB9K +8k11EPG2NZ/fyn0DmNOs3gNm7irx2LB9bgdUCxCYIU2AyxIg58xP3kV9yXJ3MurK +kLtpUhADL6jzlcXxi2JWG+9nb6QQQZWtCpvjpcCw0nB2UDBbqOgILHztp6J6jTgp +HKzH7fJ8lbCVgn1JXDjNdyXvvYB1U5Q8PcpjW58VtdMdEy8Z0TzbdjrMuH3J5cLX +2kBv2CHccxtCLVOc/hr8fat6Nj+Y3oR8BWfOahQ4h6nxjLVoy2h/cSAr9aBj9VYv +oybSt2+xWhfXOJkI/pNYb/7DE0kIFgunTWcAUjFnI06Y7VFFHbkE2Qvs2CizS73t +NnkCAwEAAaOCATowggE2MB0GA1UdDgQWBBQnjmcRdMMmHT/tM2OzpNgdMOXo1TCB +yQYDVR0jBIHBMIG+gBQnjmcRdMMmHT/tM2OzpNgdMOXo1aGBmqSBlzCBlDELMAkG +A1UEBhMCVVMxEDAOBgNVBAgMB01vbnRhbmExEDAOBgNVBAcMB0JvemVtYW4xETAP +BgNVBAoMCFNhd3Rvb3RoMRMwEQYDVQQLDApDb25zdWx0aW5nMRgwFgYDVQQDDA93 +d3cud29sZnNzbC5jb20xHzAdBgkqhkiG9w0BCQEWEGluZm9Ad29sZnNzbC5jb22C +CQCq0z+sGAo3TTAMBgNVHRMEBTADAQH/MBwGA1UdEQQVMBOCC2V4YW1wbGUuY29t +hwR/AAABMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjANBgkqhkiG9w0B +AQsFAAOCAQEAYpjIWM9WA4ZbG3FJfQUDXeAIhq3bSt6rIpaow1lowTeQQN+9idC8 +2o7vh7LCYlLhGikXapaZyE7YMv640Vw7CsI8X6EemH/OiSYhH2ScFXqc7/sdhWr6 +mM6oqavDosDrh+28Id/zB1uu/UDUriDQdooxCqJifGENzl2aHuQgiFFJ+3epzU3G +v1SZM+9LoHNwbS7ZPQj2EjkxaMZhXEG1G/Q4ffy+c2Yt98pbLFsxqs/2fzDkEiyO +1jhR5kXu1drDg9btXuzWthSzk1nhVUp/BN/OZdTfGE/dtEV/plYwxAVEmJ1PJm2E +gKBe7SPRSIcOBQaRO7A8u4yPPHtMT6HKmDGCArUwggKxAgEBMIGiMIGUMQswCQYD +VQQGEwJVUzEQMA4GA1UECAwHTW9udGFuYTEQMA4GA1UEBwwHQm96ZW1hbjERMA8G +A1UECgwIU2F3dG9vdGgxEzARBgNVBAsMCkNvbnN1bHRpbmcxGDAWBgNVBAMMD3d3 +dy53b2xmc3NsLmNvbTEfMB0GCSqGSIb3DQEJARYQaW5mb0B3b2xmc3NsLmNvbQIJ +AKrTP6wYCjdNMA0GCWCGSAFlAwQCAQUAoIHkMBgGCSqGSIb3DQEJAzELBgkqhkiG +9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTIxMDQzMDIyMDIxNVowLwYJKoZIhvcNAQkE +MSIEIK/ck17trnj+dm7BHjYDU6Vr84PBHws8jt5J5kmOBzeFMHkGCSqGSIb3DQEJ +DzFsMGowCwYJYIZIAWUDBAEqMAsGCWCGSAFlAwQBFjALBglghkgBZQMEAQIwCgYI +KoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsOAwIH +MA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIIBAIpnnr7ts2RcUhyYH0g8 +H55w+mgaX+BEZ6dPbR0Db3VIwueDXhsyyp+JQtfRo4DUPgHQtGKFFk5PsAnv122l +dMEdEx90hwtzdM1GAg/8PIMJnsKFlz+Yc2F6WsTGdCKasCpr4Tz/UiiztdCi3eJn +UGGlChnuZgUS0LRRNfSmZGdnAjVdk8yammEUFclS09z+t9NT+2UIMHeZWfsMRSit +fHjnvzbMtxF32uRbZdALMV2b8nW56y6al+/lMvj0074l4VKmKuH3Vj/EnC2PQ9xl +EG9H2hS68U8ZxPtUELh4fEUy52nubfohCpBd0CFSe7BM3CKYid+fFLQmNc5POCla +7RM= + +------7DB22CE8F405BFCE81603E2CD3794291-- + diff --git a/src/ssl.c b/src/ssl.c index 6e86a1af9..662bc962d 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -54446,11 +54446,14 @@ WOLFSSL_API PKCS7* wolfSSL_SMIME_read_PKCS7(WOLFSSL_BIO* in, int sectionLen = 0; int ret = -1; char* section = NULL; + char* canonLine = NULL; + char* canonSection = NULL; PKCS7* pkcs7 = NULL; word32 outLen = 0; byte* out = NULL; byte* outHead = NULL; + int canonPos = 0; int lineLen = 0; int remainLen = 0; byte isEnd = 0; @@ -54478,8 +54481,7 @@ WOLFSSL_API PKCS7* wolfSSL_SMIME_read_PKCS7(WOLFSSL_BIO* in, goto error; } - section = (char*)XMALLOC((remainLen+1)*sizeof(char), NULL, - DYNAMIC_TYPE_PKCS7); + section = (char*)XMALLOC(remainLen+1, NULL, DYNAMIC_TYPE_PKCS7); if (section == NULL) { goto error; } @@ -54526,12 +54528,11 @@ WOLFSSL_API PKCS7* wolfSSL_SMIME_read_PKCS7(WOLFSSL_BIO* in, } boundLen = XSTRLEN(curParam->value) + 2; - boundary = (char*)XMALLOC((boundLen+1)*sizeof(char), NULL, - DYNAMIC_TYPE_PKCS7); + boundary = (char*)XMALLOC(boundLen+1, NULL, DYNAMIC_TYPE_PKCS7); if (boundary == NULL) { goto error; } - XMEMSET(boundary, 0, (word32)((boundLen+1)*sizeof(char))); + XMEMSET(boundary, 0, (word32)(boundLen+1)); boundary[0] = boundary[1] = '-'; XSTRNCPY(&boundary[2], curParam->value, boundLen-2); @@ -54553,38 +54554,59 @@ WOLFSSL_API PKCS7* wolfSSL_SMIME_read_PKCS7(WOLFSSL_BIO* in, section[0] = '\0'; sectionLen = 0; + canonSection = (char*)XMALLOC(remainLen+1, NULL, + DYNAMIC_TYPE_PKCS7); + if (canonSection == NULL) { + goto error; + } + lineLen = wolfSSL_BIO_gets(in, section, remainLen); while(XSTRNCMP(§ion[sectionLen], boundary, boundLen) && remainLen > 0) { + canonLine = wc_MIME_canonicalize(§ion[sectionLen]); + if (canonLine == NULL) { + goto error; + } + XMEMCPY(&canonSection[canonPos], canonLine, + (int)XSTRLEN(canonLine)); + canonPos += XSTRLEN(canonLine); + 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; } } - sectionLen--; + + canonPos--; /* Strip the final trailing newline. Support \r, \n or \r\n. */ - if (section[sectionLen] == '\n') { - sectionLen--; - if (section[sectionLen] == '\r') { - sectionLen--; + if (canonSection[canonPos] == '\n') { + canonPos--; + if (canonSection[canonPos] == '\r') { + canonPos--; } } - else if (section[sectionLen] == '\r') { - sectionLen--; + else if (canonSection[canonPos] == '\r') { + canonPos--; } - section[sectionLen+1] = '\0'; + canonSection[canonPos+1] = '\0'; *bcont = wolfSSL_BIO_new(wolfSSL_BIO_s_mem()); - ret = wolfSSL_BIO_write(*bcont, section, (int)XSTRLEN(section)); - if (ret != (int)XSTRLEN(section)) { + ret = wolfSSL_BIO_write(*bcont, canonSection, + (int)XSTRLEN(canonSection)); + if (ret != (int)XSTRLEN(canonSection)) { 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); @@ -54641,6 +54663,7 @@ WOLFSSL_API PKCS7* wolfSSL_SMIME_read_PKCS7(WOLFSSL_BIO* in, } XFREE(boundary, NULL, DYNAMIC_TYPE_PKCS7); + boundary = NULL; } } else if (curHdr && (!XSTRNCMP(curHdr->body, kAppPkcs7Mime, @@ -54709,6 +54732,8 @@ error: 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); wolfSSL_BIO_free(*bcont); return NULL; diff --git a/tests/api.c b/tests/api.c index 034c07a48..7a2682f18 100644 --- a/tests/api.c +++ b/tests/api.c @@ -39333,6 +39333,15 @@ static void test_wolfSSL_SMIME_read_PKCS7(void) pkcs7 = wolfSSL_SMIME_read_PKCS7(bio, &bcont); AssertNull(pkcs7); AssertIntEQ(wolfSSL_PKCS7_verify(pkcs7, NULL, NULL, bcont, NULL, PKCS7_NOVERIFY), SSL_FAILURE); + XFCLOSE(smimeTestFile); + if (bcont) BIO_free(bcont); + wolfSSL_PKCS7_free(pkcs7); + + smimeTestFile = XFOPEN("./certs/test/smime-test-canon.p7s", "r"); + AssertIntEQ(wolfSSL_BIO_set_fp(bio, smimeTestFile, BIO_CLOSE), SSL_SUCCESS); + pkcs7 = wolfSSL_SMIME_read_PKCS7(bio, &bcont); + AssertNotNull(pkcs7); + AssertIntEQ(wolfSSL_PKCS7_verify(pkcs7, NULL, NULL, bcont, NULL, PKCS7_NOVERIFY), SSL_SUCCESS); BIO_free(bio); if (bcont) BIO_free(bcont); wolfSSL_PKCS7_free(pkcs7); diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 010be3f53..718ec2162 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -18547,13 +18547,17 @@ int wc_MIME_parse_headers(char* in, int inLen, MimeHdr** headers) } start = end = 0; lineLen = XSTRLEN(curLine); + if (lineLen == 0) { + ret = BAD_FUNC_ARG; + goto error; + } for (pos = 0; pos < lineLen; pos++) { char cur = curLine[pos]; if (mimeStatus == MIME_NAMEATTR && ((cur == ':' && mimeType == MIME_HDR) || (cur == '=' && - mimeType == MIME_PARAM))) { + mimeType == MIME_PARAM)) && pos >= 1) { mimeStatus = MIME_BODYVAL; end = pos-1; ret = wc_MIME_header_strip(curLine, &nameAttr, start, end); @@ -18562,7 +18566,7 @@ int wc_MIME_parse_headers(char* in, int inLen, MimeHdr** headers) } start = pos+1; } - else if (mimeStatus == MIME_BODYVAL && cur == ';') { + else if (mimeStatus == MIME_BODYVAL && cur == ';' && pos >= 1) { end = pos-1; ret = wc_MIME_header_strip(curLine, &bodyVal, start, end); if (ret) { @@ -18570,7 +18574,9 @@ int wc_MIME_parse_headers(char* in, int inLen, MimeHdr** headers) } if (mimeType == MIME_HDR) { nextHdr->name = nameAttr; + nameAttr = NULL; nextHdr->body = bodyVal; + bodyVal = NULL; nextHdr->next = curHdr; curHdr = nextHdr; nextHdr = (MimeHdr*)XMALLOC(sizeof(MimeHdr), NULL, @@ -18583,7 +18589,9 @@ int wc_MIME_parse_headers(char* in, int inLen, MimeHdr** headers) } else { nextParam->attribute = nameAttr; + nameAttr = NULL; nextParam->value = bodyVal; + bodyVal = NULL; nextParam->next = curHdr->params; curHdr->params = nextParam; nextParam = (MimeParam*)XMALLOC(sizeof(MimeParam), NULL, @@ -18612,7 +18620,9 @@ int wc_MIME_parse_headers(char* in, int inLen, MimeHdr** headers) } if (mimeType == MIME_HDR) { nextHdr->name = nameAttr; + nameAttr = NULL; nextHdr->body = bodyVal; + bodyVal = NULL; nextHdr->next = curHdr; curHdr = nextHdr; nextHdr = (MimeHdr*)XMALLOC(sizeof(MimeHdr), NULL, @@ -18624,7 +18634,9 @@ int wc_MIME_parse_headers(char* in, int inLen, MimeHdr** headers) XMEMSET(nextHdr, 0, (word32)sizeof(MimeHdr)); } else { nextParam->attribute = nameAttr; + nameAttr = NULL; nextParam->value = bodyVal; + bodyVal = NULL; nextParam->next = curHdr->params; curHdr->params = nextParam; nextParam = (MimeParam*)XMALLOC(sizeof(MimeParam), NULL, @@ -18650,8 +18662,10 @@ int wc_MIME_parse_headers(char* in, int inLen, MimeHdr** headers) error: wc_MIME_free_hdrs(curHdr); wc_MIME_free_hdrs(nextHdr); - XFREE(nameAttr, NULL, DYNAMIC_TYPE_PKCS7); - XFREE(bodyVal, NULL, DYNAMIC_TYPE_PKCS7); + if (nameAttr != NULL) + XFREE(nameAttr, NULL, DYNAMIC_TYPE_PKCS7); + if (bodyVal != NULL) + XFREE(bodyVal, NULL, DYNAMIC_TYPE_PKCS7); XFREE(nextParam, NULL, DYNAMIC_TYPE_PKCS7); return ret; @@ -18742,6 +18756,41 @@ MimeParam* wc_MIME_find_param_attr(const char* attribute, return param; } +/***************************************************************************** +* wc_MIME_canonicalize - Canonicalize a line by converting all line endings +* to CRLF. +* +* RETURNS: +* returns a pointer to a canonicalized line on success, NULL on error. +*/ +char* wc_MIME_canonicalize(const char* line) +{ + size_t end = 0; + char* canonLine = NULL; + + if (line == NULL || XSTRLEN(line) == 0) { + return NULL; + } + + end = XSTRLEN(line); + while (end >= 1 && ((line[end-1] == '\r') || (line[end-1] == '\n'))) { + end--; + } + + /* Need 2 chars for \r\n and 1 for EOL */ + canonLine = (char*)XMALLOC((end+3)*sizeof(char), NULL, DYNAMIC_TYPE_PKCS7); + if (canonLine == NULL) { + return NULL; + } + + XSTRNCPY(canonLine, line, end); + canonLine[end] = '\r'; + canonLine[end+1] = '\n'; + canonLine[end+2] = '\0'; + + return canonLine; +} + /***************************************************************************** * wc_MIME_free_hdrs - Frees all MIME headers, parameters and strings starting from * the provided header pointer. diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index 4bfc55545..e7cb80f6c 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -1295,6 +1295,7 @@ WOLFSSL_LOCAL int wc_MIME_create_header(char* name, char* body, MimeHdr** hdr); WOLFSSL_LOCAL int wc_MIME_create_parameter(char* attribute, char* value, MimeParam** param); WOLFSSL_LOCAL MimeHdr* wc_MIME_find_header_name(const char* name, MimeHdr* hdr); WOLFSSL_LOCAL MimeParam* wc_MIME_find_param_attr(const char* attribute, MimeParam* param); +WOLFSSL_LOCAL char* wc_MIME_canonicalize(const char* line); WOLFSSL_LOCAL int wc_MIME_free_hdrs(MimeHdr* head); #endif /* HAVE_SMIME */