Skip to content

Commit 4f68f69

Browse files
Updated size of OID represention to be word32 instead of word16 so OIDs
will not be truncated. Added tests for updated OID handling. made change fips compatable removed tests for EncodeObjectId caused symbol error in CI/CD
1 parent c685293 commit 4f68f69

7 files changed

Lines changed: 486 additions & 106 deletions

File tree

doc/dox_comments/header_files/asn.h

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,16 @@ void FreeAltNames(DNS_entry* altNames, void* heap);
8080
\note This API is not public by default. Define WOLFSSL_PUBLIC_ASN to
8181
expose APIs marked WOLFSSL_ASN_API.
8282
83+
\note The oid argument passed to the callback is an array of word32
84+
elements, one per OID arc, so that arcs > 65535 are represented without
85+
truncation. Callbacks must declare their oid parameter as const word32*.
86+
The same applies to wc_SetUnknownExtCallback.
87+
8388
_Example_
8489
\code
8590
DecodedCert cert;
8691
87-
int UnknownExtCallback(const byte* oid, word32 oidSz, int crit,
92+
int UnknownExtCallback(const word32* oid, word32 oidSz, int crit,
8893
const byte* der, word32 derSz, void* ctx) {
8994
// handle unknown extension
9095
return 0;
@@ -140,28 +145,31 @@ int wc_CheckCertSignature(const byte* cert, word32 certSz, void* heap,
140145

141146
/*!
142147
\ingroup ASN
143-
\brief This function encodes an array of word16 values into an ASN.1
148+
\brief This function encodes an array of word32 values into an ASN.1
144149
Object Identifier (OID) in DER format. OIDs are used to identify
145150
algorithms, extensions, and other objects in certificates and
146151
cryptographic protocols.
147152
153+
Each OID arc is a word32, so OIDs containing arcs with values > 65535 are
154+
represented without truncation.
155+
148156
\return 0 On success.
149157
\return BAD_FUNC_ARG If in, inSz, or outSz are invalid.
150158
\return BUFFER_E If out is not NULL and outSz is too small.
151159
152-
\param in pointer to array of word16 values representing OID components
160+
\param in pointer to array of word32 values representing OID components
153161
\param inSz number of components in the OID
154162
\param out pointer to buffer to store encoded OID (can be NULL to
155163
calculate size)
156164
\param outSz pointer to size of out buffer; updated with actual size
157165
158166
_Example_
159167
\code
160-
word16 oid[] = {1, 2, 840, 113549, 1, 1, 11}; // sha256WithRSAEncryption
168+
word32 oid[] = {1, 2, 840, 113549, 1, 1, 11}; // sha256WithRSAEncryption
161169
byte encoded[32];
162170
word32 encodedSz = sizeof(encoded);
163171
164-
int ret = wc_EncodeObjectId(oid, sizeof(oid)/sizeof(word16),
172+
int ret = wc_EncodeObjectId(oid, sizeof(oid)/sizeof(*oid),
165173
encoded, &encodedSz);
166174
if (ret == 0) {
167175
// encoded contains DER encoded OID
@@ -170,7 +178,7 @@ int wc_CheckCertSignature(const byte* cert, word32 certSz, void* heap,
170178
171179
\sa wc_BerToDer
172180
*/
173-
int wc_EncodeObjectId(const word16* in, word32 inSz, byte* out,
181+
int wc_EncodeObjectId(const word32* in, word32 inSz, byte* out,
174182
word32* outSz);
175183

176184
/*!

doc/dox_comments/header_files/asn_public.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3953,7 +3953,7 @@ int wc_SetCustomExtension(Cert *cert, int critical, const char *oid,
39533953
\code
39543954
int ret = 0;
39553955
// Unknown extension callback prototype
3956-
int myUnknownExtCallback(const word16* oid, word32 oidSz, int crit,
3956+
int myUnknownExtCallback(const word32* oid, word32 oidSz, int crit,
39573957
const unsigned char* der, word32 derSz);
39583958
39593959
// Register it
@@ -3967,7 +3967,7 @@ int wc_SetCustomExtension(Cert *cert, int critical, const char *oid,
39673967
// crit: Whether the extension was mark critical.
39683968
// der: The der encoding of the content of the extension.
39693969
// derSz: The size in bytes of the der encoding.
3970-
int myCustomExtCallback(const word16* oid, word32 oidSz, int crit,
3970+
int myCustomExtCallback(const word32* oid, word32 oidSz, int crit,
39713971
const unsigned char* der, word32 derSz) {
39723972
39733973
// Logic to parse extension goes here.

tests/api/test_asn.c

Lines changed: 266 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1624,36 +1624,49 @@ int test_SerialNumber0_RootCA(void)
16241624
return EXPECT_RESULT();
16251625
}
16261626

1627-
int test_wc_DecodeObjectId(void)
1627+
1628+
int test_wc_DecodeObjectId_FIPS16(void)
16281629
{
16291630
EXPECT_DECLS;
16301631

16311632
#if !defined(NO_ASN) && \
16321633
(defined(HAVE_OID_DECODING) || defined(WOLFSSL_ASN_PRINT))
16331634
{
1634-
/* OID 1.2.840.113549.1.1.11 (sha256WithRSAEncryption)
1635-
* DER encoding: 2a 86 48 86 f7 0d 01 01 0b
1636-
* First byte 0x2a = 42 => arc0 = 42/40 = 1, arc1 = 42%40 = 2
1637-
* Remaining arcs: 840, 113549, 1, 1, 11
1635+
word32 i;
1636+
static const word16 oid_dot_2[] = {
1637+
2, 100, 4, 6
1638+
};
1639+
1640+
static const byte oid_start_with_2[] = {
1641+
0x81, 0x34, 0x04, 0x06
1642+
};
1643+
1644+
1645+
/* OID 1.3.132.0.6 (secp112r1)
1646+
* DER encoding: 2b 81 04 00 06
1647+
* First byte 0x2b = 43 => arc0 = 43/40 = 1, arc1 = 43%40 = 3
1648+
* Remaining arcs: 132 0 6
16381649
*/
16391650
static const byte oid_sha256rsa[] = {
1640-
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b
1651+
0x2B, 0x81, 0x04, 0x00, 0x06
1652+
};
1653+
1654+
static const word16 oid_dot_form[] = {
1655+
1U, 3U, 132U, 0U, 6U
16411656
};
1657+
16421658
word16 out[MAX_OID_SZ];
16431659
word32 outSz;
16441660

1661+
word32 trueOutSz = sizeof(oid_dot_form) / sizeof(*oid_dot_form);
16451662
/* Test 1: Normal decode */
16461663
outSz = MAX_OID_SZ;
16471664
ExpectIntEQ(DecodeObjectId(oid_sha256rsa, sizeof(oid_sha256rsa),
16481665
out, &outSz), 0);
1649-
ExpectIntEQ((int)outSz, 7);
1650-
ExpectIntEQ(out[0], 1);
1651-
ExpectIntEQ(out[1], 2);
1652-
ExpectIntEQ(out[2], 840);
1653-
ExpectIntEQ(out[3], (word16)113549); /* truncated to word16 */
1654-
ExpectIntEQ(out[4], 1);
1655-
ExpectIntEQ(out[5], 1);
1656-
ExpectIntEQ(out[6], 11);
1666+
ExpectIntEQ((int)outSz, trueOutSz);
1667+
for (i = 0; i < ((outSz <= trueOutSz) ? outSz : trueOutSz); i++) {
1668+
ExpectIntEQ(out[i], oid_dot_form[i]);
1669+
}
16571670

16581671
/* Test 2: NULL args */
16591672
outSz = MAX_OID_SZ;
@@ -1692,12 +1705,251 @@ int test_wc_DecodeObjectId(void)
16921705
ExpectIntEQ(DecodeObjectId(oid_sha256rsa, sizeof(oid_sha256rsa),
16931706
out, &outSz),
16941707
WC_NO_ERR_TRACE(BUFFER_E));
1708+
1709+
/* Test 7: first Arc is 2 */
1710+
{
1711+
word32 trueOutSz2 = sizeof(oid_dot_2) / sizeof(*oid_dot_2);
1712+
outSz = MAX_OID_SZ;
1713+
ExpectIntEQ(DecodeObjectId(oid_start_with_2,
1714+
sizeof(oid_start_with_2),
1715+
out, &outSz), 0);
1716+
ExpectIntEQ((int)outSz, trueOutSz2);
1717+
for (i = 0; i < ((outSz <= trueOutSz2) ?
1718+
outSz : trueOutSz2); i++) {
1719+
ExpectIntEQ(out[i], oid_dot_2[i]);
1720+
}
1721+
}
1722+
1723+
/* Test 8: an OID with an arc that exceeds word16. Tests that wrong
1724+
* but unchangable behavior is workign correctly,
1725+
*
1726+
* word16 version is used in FIPS build
1727+
*/
1728+
{
1729+
static const byte oid_large_arc[] = {
1730+
0x2a, 0x86, 0x48, 0x82, 0xf7, 0x0d, 0x01, 0x01, 0x0b
1731+
};
1732+
static const word16 oid_dot_large_arc[] = {
1733+
1U, 2U, 840U, (word16)113549U, 1U, 1U, 11U
1734+
};
1735+
word32 trueOutSz3 = sizeof(oid_dot_large_arc) / sizeof(word16);
1736+
1737+
outSz = MAX_OID_SZ;
1738+
ExpectIntEQ(DecodeObjectId(oid_large_arc, sizeof(oid_large_arc),
1739+
out, &outSz), 0);
1740+
ExpectIntEQ((int)outSz, (int)trueOutSz3);
1741+
for (i = 0; i < ((outSz <= trueOutSz3) ? outSz : trueOutSz3); i++) {
1742+
ExpectIntEQ(out[i], oid_dot_large_arc[i]);
1743+
}
1744+
#undef LARGE_ARC_EXPECTED
1745+
}
16951746
}
16961747
#endif /* !NO_ASN && (HAVE_OID_DECODING || WOLFSSL_ASN_PRINT) */
16971748

16981749
return EXPECT_RESULT();
16991750
}
17001751

1752+
/* Test for word16 FIPS version of function */
1753+
int test_wc_DecodeObjectId_ex(void)
1754+
{
1755+
EXPECT_DECLS;
1756+
1757+
#if !defined(NO_ASN) && \
1758+
(defined(HAVE_OID_DECODING) || defined(WOLFSSL_ASN_PRINT))
1759+
{
1760+
word32 i;
1761+
static const word32 oid_dot_2[] = {
1762+
2, 100, 4, 6
1763+
};
1764+
1765+
static const byte oid_start_with_2[] = {
1766+
0x81, 0x34, 0x04, 0x06
1767+
};
1768+
1769+
1770+
/* OID 1.3.132.0.6 (secp112r1)
1771+
* DER encoding: 2b 81 04 00 06
1772+
* First byte 0x2b = 43 => arc0 = 43/40 = 1, arc1 = 43%40 = 3
1773+
* Remaining arcs: 132 0 6
1774+
*/
1775+
static const byte oid_sha256rsa[] = {
1776+
0x2B, 0x81, 0x04, 0x00, 0x06
1777+
};
1778+
1779+
static const word32 oid_dot_form[] = {
1780+
1U, 3U, 132U, 0U, 6U
1781+
};
1782+
1783+
word32 out[MAX_OID_SZ];
1784+
word32 outSz;
1785+
1786+
word32 trueOutSz = sizeof(oid_dot_form) / sizeof(word32);
1787+
/* Test 1: Normal decode */
1788+
outSz = MAX_OID_SZ;
1789+
ExpectIntEQ(DecodeObjectId_ex(oid_sha256rsa, sizeof(oid_sha256rsa),
1790+
out, &outSz), 0);
1791+
ExpectIntEQ((int)outSz, trueOutSz);
1792+
for (i = 0; i < ((outSz <= trueOutSz) ? outSz : trueOutSz); i++) {
1793+
ExpectIntEQ(out[i], oid_dot_form[i]);
1794+
}
1795+
1796+
/* Test 2: NULL args */
1797+
outSz = MAX_OID_SZ;
1798+
ExpectIntEQ(DecodeObjectId_ex(NULL, sizeof(oid_sha256rsa), out, &outSz),
1799+
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
1800+
ExpectIntEQ(DecodeObjectId_ex(oid_sha256rsa, sizeof(oid_sha256rsa),
1801+
out, NULL),
1802+
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
1803+
1804+
/* Test 3 (Bug 1): outSz=1 must return BUFFER_E, not OOB write.
1805+
* The first OID byte decodes into two arcs, so outSz must be >= 2. */
1806+
outSz = 1;
1807+
ExpectIntEQ(DecodeObjectId_ex(oid_sha256rsa, sizeof(oid_sha256rsa),
1808+
out, &outSz),
1809+
WC_NO_ERR_TRACE(BUFFER_E));
1810+
1811+
/* Test 4: outSz=0 must also return BUFFER_E */
1812+
outSz = 0;
1813+
ExpectIntEQ(DecodeObjectId_ex(oid_sha256rsa, sizeof(oid_sha256rsa),
1814+
out, &outSz),
1815+
WC_NO_ERR_TRACE(BUFFER_E));
1816+
1817+
/* Test 5: outSz=2 is enough for a single-byte OID (two arcs) */
1818+
{
1819+
static const byte oid_one_byte[] = { 0x2a }; /* 1.2 */
1820+
outSz = 2;
1821+
ExpectIntEQ(DecodeObjectId_ex(oid_one_byte, sizeof(oid_one_byte),
1822+
out, &outSz), 0);
1823+
ExpectIntEQ((int)outSz, 2);
1824+
ExpectIntEQ(out[0], 1);
1825+
ExpectIntEQ(out[1], 2);
1826+
}
1827+
1828+
/* Test 6: Buffer too small for later arcs */
1829+
outSz = 3; /* only room for 3 arcs, but OID has 7 */
1830+
ExpectIntEQ(DecodeObjectId_ex(oid_sha256rsa, sizeof(oid_sha256rsa),
1831+
out, &outSz),
1832+
WC_NO_ERR_TRACE(BUFFER_E));
1833+
1834+
/* Test 7: first Arc is 2 */
1835+
{
1836+
word32 trueOutSz2 = sizeof(oid_dot_2) / sizeof(word32);
1837+
outSz = MAX_OID_SZ;
1838+
ExpectIntEQ(DecodeObjectId_ex(oid_start_with_2,
1839+
sizeof(oid_start_with_2),
1840+
out, &outSz), 0);
1841+
ExpectIntEQ((int)outSz, trueOutSz2);
1842+
for (i = 0; i < ((outSz <= trueOutSz2) ?
1843+
outSz : trueOutSz2); i++) {
1844+
ExpectIntEQ(out[i], oid_dot_2[i]);
1845+
}
1846+
}
1847+
1848+
/* Test 8: an OID with an arc that exceeds word16.
1849+
*/
1850+
{
1851+
static const byte oid_large_arc[] = {
1852+
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b
1853+
};
1854+
static const word32 oid_dot_large_arc[] = {
1855+
1U, 2U, 840U, 113549U, 1U, 1U, 11U
1856+
};
1857+
word32 trueOutSz3 = sizeof(oid_dot_large_arc) / sizeof(word32);
1858+
1859+
outSz = MAX_OID_SZ;
1860+
ExpectIntEQ(DecodeObjectId_ex(oid_large_arc, sizeof(oid_large_arc),
1861+
out, &outSz), 0);
1862+
ExpectIntEQ((int)outSz, (int)trueOutSz3);
1863+
for (i = 0; i < ((outSz <= trueOutSz3) ? outSz : trueOutSz3); i++) {
1864+
ExpectIntEQ(out[i], oid_dot_large_arc[i]);
1865+
}
1866+
#undef LARGE_ARC_EXPECTED
1867+
}
1868+
}
1869+
#endif /* !NO_ASN && (HAVE_OID_DECODING || WOLFSSL_ASN_PRINT) */
1870+
1871+
return EXPECT_RESULT();
1872+
}
1873+
1874+
int test_wc_EncodeObjectId(void)
1875+
{
1876+
EXPECT_DECLS;
1877+
#if defined(HAVE_OID_ENCODING) && !defined(NO_ASN)
1878+
{
1879+
/* 1.3.132.0.6 (secp112r1) -- every arc fits in word16, so this
1880+
* encodes identically in both build configs. */
1881+
static const word32 oid_small[] = { 1U, 3U, 132U, 0U, 6U };
1882+
static const byte oid_small_der[] = {
1883+
0x2b, 0x81, 0x04, 0x00, 0x06
1884+
};
1885+
const word32 oid_small_cnt = sizeof(oid_small) / sizeof(word32);
1886+
byte out[MAX_OID_SZ];
1887+
word32 outSz;
1888+
word32 i;
1889+
1890+
/* Test 1: length-only query (out == NULL) */
1891+
outSz = 0;
1892+
ExpectIntEQ(wc_EncodeObjectId(oid_small, oid_small_cnt, NULL, &outSz),
1893+
0);
1894+
ExpectIntEQ((int)outSz, (int)sizeof(oid_small_der));
1895+
1896+
/* Test 2: normal encode matches expected DER */
1897+
outSz = sizeof(out);
1898+
ExpectIntEQ(wc_EncodeObjectId(oid_small, oid_small_cnt, out, &outSz), 0);
1899+
ExpectIntEQ((int)outSz, (int)sizeof(oid_small_der));
1900+
for (i = 0; i < outSz && i < sizeof(oid_small_der); i++) {
1901+
ExpectIntEQ(out[i], oid_small_der[i]);
1902+
}
1903+
1904+
/* Test 3: NULL args */
1905+
outSz = sizeof(out);
1906+
ExpectIntEQ(wc_EncodeObjectId(NULL, oid_small_cnt, out, &outSz),
1907+
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
1908+
ExpectIntEQ(wc_EncodeObjectId(oid_small, oid_small_cnt, out, NULL),
1909+
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
1910+
1911+
/* Test 4: output buffer too small */
1912+
outSz = 1;
1913+
ExpectIntEQ(wc_EncodeObjectId(oid_small, oid_small_cnt, out, &outSz),
1914+
WC_NO_ERR_TRACE(BUFFER_E));
1915+
1916+
/* Test 5 ): an arc > word16 can only be represented in the
1917+
*/
1918+
{
1919+
static const word32 oid_large[] = {
1920+
1U, 2U, 840U, 113549U, 1U, 1U, 11U
1921+
};
1922+
static const byte oid_large_der[] = {
1923+
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b
1924+
};
1925+
const word32 oid_large_cnt = sizeof(oid_large) / sizeof(word32);
1926+
1927+
outSz = sizeof(out);
1928+
ExpectIntEQ(wc_EncodeObjectId(oid_large, oid_large_cnt, out, &outSz),
1929+
0);
1930+
ExpectIntEQ((int)outSz, (int)sizeof(oid_large_der));
1931+
for (i = 0; i < outSz && i < sizeof(oid_large_der); i++) {
1932+
ExpectIntEQ(out[i], oid_large_der[i]);
1933+
}
1934+
1935+
#if defined(HAVE_OID_DECODING) || defined(WOLFSSL_ASN_PRINT)
1936+
{
1937+
word32 dec[MAX_OID_SZ];
1938+
word32 decSz = MAX_OID_SZ;
1939+
ExpectIntEQ(DecodeObjectId_ex(out, outSz, dec, &decSz), 0);
1940+
ExpectIntEQ((int)decSz, (int)oid_large_cnt);
1941+
for (i = 0; i < decSz && i < oid_large_cnt; i++) {
1942+
ExpectIntEQ(dec[i], oid_large[i]);
1943+
}
1944+
}
1945+
#endif /* HAVE_OID_DECODING || WOLFSSL_ASN_PRINT */
1946+
}
1947+
}
1948+
#endif /* HAVE_OID_ENCODING && !NO_ASN */
1949+
1950+
return EXPECT_RESULT();
1951+
}
1952+
17011953
#if defined(HAVE_PKCS8) && !defined(NO_ASN) && \
17021954
(defined(WOLFSSL_TEST_CERT) || defined(OPENSSL_EXTRA) || \
17031955
defined(OPENSSL_EXTRA_X509_SMALL) || defined(WOLFSSL_PUBLIC_ASN)) && \

0 commit comments

Comments
 (0)