mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-05 14:30:49 +02:00
Fix CertFromX509 copy length check
This commit is contained in:
+19
-16
@@ -11870,25 +11870,28 @@ static int CertFromX509(Cert* cert, WOLFSSL_X509* x509)
|
||||
return WOLFSSL_FAILURE;
|
||||
}
|
||||
|
||||
if (x509->authKeyIdSz < sizeof(cert->akid)) {
|
||||
#ifdef WOLFSSL_AKID_NAME
|
||||
cert->rawAkid = 0;
|
||||
if (x509->authKeyIdSrc) {
|
||||
XMEMCPY(cert->akid, x509->authKeyIdSrc, x509->authKeyIdSrcSz);
|
||||
cert->akidSz = (int)x509->authKeyIdSrcSz;
|
||||
cert->rawAkid = 1;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (x509->authKeyId) {
|
||||
XMEMCPY(cert->akid, x509->authKeyId, x509->authKeyIdSz);
|
||||
cert->akidSz = (int)x509->authKeyIdSz;
|
||||
cert->rawAkid = 0;
|
||||
if (x509->authKeyIdSrc) {
|
||||
if (x509->authKeyIdSrcSz > sizeof(cert->akid)) {
|
||||
WOLFSSL_MSG("Auth Key ID too large");
|
||||
WOLFSSL_ERROR_VERBOSE(BUFFER_E);
|
||||
return WOLFSSL_FAILURE;
|
||||
}
|
||||
XMEMCPY(cert->akid, x509->authKeyIdSrc, x509->authKeyIdSrcSz);
|
||||
cert->akidSz = (int)x509->authKeyIdSrcSz;
|
||||
cert->rawAkid = 1;
|
||||
}
|
||||
else {
|
||||
WOLFSSL_MSG("Auth Key ID too large");
|
||||
WOLFSSL_ERROR_VERBOSE(BUFFER_E);
|
||||
return WOLFSSL_FAILURE;
|
||||
else
|
||||
#endif
|
||||
if (x509->authKeyId) {
|
||||
if (x509->authKeyIdSz > sizeof(cert->akid)) {
|
||||
WOLFSSL_MSG("Auth Key ID too large");
|
||||
WOLFSSL_ERROR_VERBOSE(BUFFER_E);
|
||||
return WOLFSSL_FAILURE;
|
||||
}
|
||||
XMEMCPY(cert->akid, x509->authKeyId, x509->authKeyIdSz);
|
||||
cert->akidSz = (int)x509->authKeyIdSz;
|
||||
}
|
||||
|
||||
for (i = 0; i < x509->certPoliciesNb; i++) {
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
|
||||
#include <wolfssl/internal.h>
|
||||
#include <wolfssl/wolfcrypt/asn.h>
|
||||
#include <wolfssl/wolfcrypt/asn_public.h>
|
||||
|
||||
#if defined(OPENSSL_ALL) && \
|
||||
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES)
|
||||
@@ -632,3 +633,218 @@ int test_x509_time_field_overread_via_tls(void)
|
||||
#endif /* compile guards */
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
|
||||
/* Test that CertFromX509 rejects an oversized raw AuthorityKeyIdentifier
|
||||
* extension. Before the fix, the guard checked authKeyIdSz (the [0]
|
||||
* keyIdentifier sub-field) but the WOLFSSL_AKID_NAME branch copied
|
||||
* authKeyIdSrcSz (the full extension) bytes, causing a heap overflow. */
|
||||
int test_x509_CertFromX509_akid_overflow(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(WOLFSSL_AKID_NAME) && defined(WOLFSSL_CERT_GEN) && \
|
||||
defined(WOLFSSL_CERT_EXT) && \
|
||||
(defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL))
|
||||
/* DER builder helpers -- write into a flat buffer */
|
||||
unsigned char buf[16384];
|
||||
size_t pos = 0;
|
||||
size_t akid_val_len;
|
||||
unsigned char* akid_val = NULL;
|
||||
WOLFSSL_X509* x = NULL;
|
||||
WOLFSSL_BIO* bio = NULL;
|
||||
|
||||
#define PUT1(b) do { buf[pos++] = (b); } while(0)
|
||||
#define PUTN(p, n) do { XMEMCPY(buf + pos, (p), (n)); pos += (n); } while(0)
|
||||
|
||||
/* Emit tag + definite-length header, return header size */
|
||||
#define TLV_HDR(tag, n, out, hlen) do { \
|
||||
size_t _i = 0; \
|
||||
(out)[_i++] = (tag); \
|
||||
if ((n) < 0x80u) { (out)[_i++] = (unsigned char)(n); } \
|
||||
else if ((n) < 0x100u) { (out)[_i++] = 0x81; \
|
||||
(out)[_i++] = (unsigned char)(n); } \
|
||||
else if ((n) < 0x10000u) { (out)[_i++] = 0x82; \
|
||||
(out)[_i++] = (unsigned char)((n)>>8); \
|
||||
(out)[_i++] = (unsigned char)(n); } \
|
||||
(hlen) = _i; \
|
||||
} while(0)
|
||||
|
||||
/* Wrap [start, pos) in-place with a TLV header */
|
||||
#define WRAP(start, tag) do { \
|
||||
size_t _len = pos - (start); \
|
||||
unsigned char _hdr[6]; size_t _hlen; \
|
||||
TLV_HDR((tag), _len, _hdr, _hlen); \
|
||||
XMEMMOVE(buf + (start) + _hlen, buf + (start), _len); \
|
||||
XMEMCPY(buf + (start), _hdr, _hlen); \
|
||||
pos += _hlen; \
|
||||
} while(0)
|
||||
|
||||
/* ---- Build AKID extension value ---- */
|
||||
{
|
||||
size_t akid_start = pos;
|
||||
size_t s;
|
||||
int i;
|
||||
|
||||
/* [0] keyIdentifier: 20 bytes (small, passes old check) */
|
||||
s = pos;
|
||||
for (i = 0; i < 20; i++) PUT1(0x41);
|
||||
WRAP(s, 0x80);
|
||||
|
||||
/* [1] authorityCertIssuer: one URI of ~4000 bytes
|
||||
* This makes authKeyIdSrcSz >> sizeof(cert->akid) (~1628) */
|
||||
s = pos;
|
||||
{
|
||||
const char* pfx = "http://e/";
|
||||
PUTN(pfx, (size_t)XSTRLEN(pfx));
|
||||
for (i = 0; i < 4000; i++) PUT1('Z');
|
||||
}
|
||||
WRAP(s, 0x86); /* GeneralName [6] URI */
|
||||
WRAP(s, 0xA1); /* [1] IMPLICIT */
|
||||
|
||||
/* [2] authorityCertSerialNumber */
|
||||
s = pos;
|
||||
PUT1(0x01);
|
||||
WRAP(s, 0x82);
|
||||
|
||||
WRAP(akid_start, 0x30); /* SEQUENCE */
|
||||
akid_val_len = pos - akid_start;
|
||||
akid_val = (unsigned char*)XMALLOC(akid_val_len, NULL,
|
||||
DYNAMIC_TYPE_TMP_BUFFER);
|
||||
ExpectNotNull(akid_val);
|
||||
if (akid_val != NULL)
|
||||
XMEMCPY(akid_val, buf + akid_start, akid_val_len);
|
||||
}
|
||||
|
||||
/* ---- Build minimal self-signed v3 certificate ---- */
|
||||
pos = 0;
|
||||
{
|
||||
size_t tbs_start = pos;
|
||||
size_t s;
|
||||
int i;
|
||||
|
||||
/* version [0] EXPLICIT INTEGER 2 (v3) */
|
||||
PUT1(0xA0); PUT1(0x03); PUT1(0x02); PUT1(0x01); PUT1(0x02);
|
||||
|
||||
/* serialNumber INTEGER 1 */
|
||||
PUT1(0x02); PUT1(0x01); PUT1(0x01);
|
||||
|
||||
/* signature: ecdsa-with-SHA256 */
|
||||
s = pos;
|
||||
{
|
||||
unsigned char oid[] = {0x06,0x08,0x2A,0x86,0x48,0xCE,
|
||||
0x3D,0x04,0x03,0x02};
|
||||
PUTN(oid, sizeof(oid));
|
||||
}
|
||||
WRAP(s, 0x30);
|
||||
|
||||
/* issuer: CN=A */
|
||||
s = pos;
|
||||
{
|
||||
size_t rdn = pos, atv = pos;
|
||||
unsigned char cn[] = {0x06,0x03,0x55,0x04,0x03};
|
||||
PUTN(cn, sizeof(cn));
|
||||
PUT1(0x0C); PUT1(0x01); PUT1('A');
|
||||
WRAP(atv, 0x30); WRAP(rdn, 0x31); WRAP(s, 0x30);
|
||||
}
|
||||
|
||||
/* validity */
|
||||
s = pos;
|
||||
{
|
||||
unsigned char t1[] = {0x17,0x0D,'2','5','0','1','0','1',
|
||||
'0','0','0','0','0','0','Z'};
|
||||
unsigned char t2[] = {0x17,0x0D,'3','5','0','1','0','1',
|
||||
'0','0','0','0','0','0','Z'};
|
||||
PUTN(t1, sizeof(t1)); PUTN(t2, sizeof(t2));
|
||||
}
|
||||
WRAP(s, 0x30);
|
||||
|
||||
/* subject: CN=A */
|
||||
s = pos;
|
||||
{
|
||||
size_t rdn = pos, atv = pos;
|
||||
unsigned char cn[] = {0x06,0x03,0x55,0x04,0x03};
|
||||
PUTN(cn, sizeof(cn));
|
||||
PUT1(0x0C); PUT1(0x01); PUT1('A');
|
||||
WRAP(atv, 0x30); WRAP(rdn, 0x31); WRAP(s, 0x30);
|
||||
}
|
||||
|
||||
/* subjectPublicKeyInfo: EC P-256 with dummy point */
|
||||
s = pos;
|
||||
{
|
||||
size_t alg = pos, bs;
|
||||
unsigned char ecpk[] = {0x06,0x07,0x2A,0x86,0x48,0xCE,
|
||||
0x3D,0x02,0x01};
|
||||
unsigned char p256[] = {0x06,0x08,0x2A,0x86,0x48,0xCE,
|
||||
0x3D,0x03,0x01,0x07};
|
||||
PUTN(ecpk, sizeof(ecpk));
|
||||
PUTN(p256, sizeof(p256));
|
||||
WRAP(alg, 0x30);
|
||||
bs = pos;
|
||||
PUT1(0x00); PUT1(0x04);
|
||||
for (i = 0; i < 64; i++) PUT1(0x01);
|
||||
WRAP(bs, 0x03);
|
||||
}
|
||||
WRAP(s, 0x30);
|
||||
|
||||
/* extensions [3] */
|
||||
{
|
||||
size_t exts_outer = pos, exts_seq = pos, ext = pos, ev;
|
||||
unsigned char akid_oid[] = {0x06,0x03,0x55,0x1D,0x23};
|
||||
PUTN(akid_oid, sizeof(akid_oid));
|
||||
ev = pos;
|
||||
if (akid_val != NULL)
|
||||
PUTN(akid_val, akid_val_len);
|
||||
WRAP(ev, 0x04);
|
||||
WRAP(ext, 0x30);
|
||||
WRAP(exts_seq, 0x30);
|
||||
WRAP(exts_outer, 0xA3);
|
||||
}
|
||||
|
||||
WRAP(tbs_start, 0x30);
|
||||
|
||||
/* signatureAlgorithm */
|
||||
s = pos;
|
||||
{
|
||||
unsigned char oid[] = {0x06,0x08,0x2A,0x86,0x48,0xCE,
|
||||
0x3D,0x04,0x03,0x02};
|
||||
PUTN(oid, sizeof(oid));
|
||||
}
|
||||
WRAP(s, 0x30);
|
||||
|
||||
/* signatureValue: dummy */
|
||||
s = pos;
|
||||
{
|
||||
size_t sig;
|
||||
PUT1(0x00);
|
||||
sig = pos;
|
||||
PUT1(0x02); PUT1(0x01); PUT1(0x01);
|
||||
PUT1(0x02); PUT1(0x01); PUT1(0x01);
|
||||
WRAP(sig, 0x30);
|
||||
}
|
||||
WRAP(s, 0x03);
|
||||
|
||||
WRAP(0, 0x30); /* outer Certificate SEQUENCE */
|
||||
}
|
||||
|
||||
/* Parse the crafted certificate */
|
||||
x = wolfSSL_X509_d2i(NULL, buf, (int)pos);
|
||||
ExpectNotNull(x);
|
||||
|
||||
/* Attempt re-encode via i2d_X509_bio -- must fail gracefully, not
|
||||
* overflow. Before the fix this would write ~4000 bytes past the
|
||||
* end of cert->akid[]. */
|
||||
bio = wolfSSL_BIO_new(wolfSSL_BIO_s_mem());
|
||||
ExpectNotNull(bio);
|
||||
ExpectIntEQ(wolfSSL_i2d_X509_bio(bio, x), 0);
|
||||
|
||||
wolfSSL_BIO_free(bio);
|
||||
wolfSSL_X509_free(x);
|
||||
XFREE(akid_val, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
|
||||
#undef PUT1
|
||||
#undef PUTN
|
||||
#undef TLV_HDR
|
||||
#undef WRAP
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
@@ -27,12 +27,14 @@ int test_x509_GetCAByAKID(void);
|
||||
int test_x509_set_serialNumber(void);
|
||||
int test_x509_verify_cert_hostname_check(void);
|
||||
int test_x509_time_field_overread_via_tls(void);
|
||||
int test_x509_CertFromX509_akid_overflow(void);
|
||||
|
||||
#define TEST_X509_DECLS \
|
||||
TEST_DECL_GROUP("x509", test_x509_rfc2818_verification_callback), \
|
||||
TEST_DECL_GROUP("x509", test_x509_GetCAByAKID), \
|
||||
TEST_DECL_GROUP("x509", test_x509_set_serialNumber), \
|
||||
TEST_DECL_GROUP("x509", test_x509_verify_cert_hostname_check), \
|
||||
TEST_DECL_GROUP("x509", test_x509_time_field_overread_via_tls)
|
||||
TEST_DECL_GROUP("x509", test_x509_time_field_overread_via_tls), \
|
||||
TEST_DECL_GROUP("x509", test_x509_CertFromX509_akid_overflow)
|
||||
|
||||
#endif /* WOLFCRYPT_TEST_X509_H */
|
||||
|
||||
Reference in New Issue
Block a user