diff --git a/src/internal.c b/src/internal.c index 9349f48c9..4dbf39b4d 100644 --- a/src/internal.c +++ b/src/internal.c @@ -4238,6 +4238,10 @@ void InitX509(WOLFSSL_X509* x509, int dynamicFlag, void* heap) /* Free wolfSSL X509 type */ void FreeX509(WOLFSSL_X509* x509) { + #if defined(WOLFSSL_CERT_REQ) && defined(OPENSSL_ALL) \ + && defined( WOLFSSL_CUSTOM_OID) + int idx; + #endif /* WOLFSSL_CERT_REQ && OPENSSL_ALL && WOLFSSL_CUSTOM_OID */ if (x509 == NULL) return; @@ -4318,7 +4322,15 @@ void FreeX509(WOLFSSL_X509* x509) if (x509->reqAttributes) { wolfSSL_sk_pop_free(x509->reqAttributes, NULL); } - #endif /* WOLFSSL_CERT_REQ */ + #ifdef WOLFSSL_CUSTOM_OID + for (idx = 0; idx < x509->customExtCount; idx++) { + XFREE(x509->custom_exts[idx].oid, x509->heap, + DYNAMIC_TYPE_X509_EXT); + XFREE(x509->custom_exts[idx].val, x509->heap, + DYNAMIC_TYPE_X509_EXT); + } + #endif /* WOLFSSL_CUSTOM_OID */ + #endif /* WOLFSSL_CERT_REQ && OPENSSL_ALL */ if (x509->altNames) { FreeAltNames(x509->altNames, x509->heap); x509->altNames = NULL; diff --git a/src/x509.c b/src/x509.c index b0b2366a8..c8fcebfb2 100644 --- a/src/x509.c +++ b/src/x509.c @@ -282,6 +282,55 @@ WOLFSSL_X509_EXTENSION* wolfSSL_X509_EXTENSION_dup(WOLFSSL_X509_EXTENSION* src) return ret; } +WOLFSSL_X509_EXTENSION* wolfSSL_X509_EXTENSION_create_by_OBJ( + WOLFSSL_X509_EXTENSION* ex, WOLFSSL_ASN1_OBJECT *obj, int crit, + WOLFSSL_ASN1_STRING *data) +{ + int err = 0; + WOLFSSL_X509_EXTENSION *ret = ex; + + WOLFSSL_ENTER("wolfSSL_X509_EXTENSION_create_by_OBJ"); + + if ((obj == NULL) || (data == NULL)) { + return NULL; + } + + if (ret == NULL) { + ret = wolfSSL_X509_EXTENSION_new(); + if (ret == NULL) { + err = 1; + } + } else { + /* Prevent potential memory leaks and dangling pointers. */ + wolfSSL_ASN1_OBJECT_free(ret->obj); + ret->obj = NULL; + wolfSSL_ASN1_STRING_free(&ret->value); + } + + ret->crit = crit; + + if (err == 0) { + ret->obj = wolfSSL_ASN1_OBJECT_dup(obj); + if (ret->obj == NULL) { + err = 1; + } + } + + if (err == 0) { + if (wolfSSL_ASN1_STRING_copy(&ret->value, data) != WOLFSSL_SUCCESS) { + err = 1; + } + } + + if (err == 1) { + if (ret != ex) { + wolfSSL_X509_EXTENSION_free(ret); + } + ret = NULL; + } + return ret; +} + /* Creates and returns a new WOLFSSL_X509_EXTENSION stack. */ WOLFSSL_STACK* wolfSSL_sk_new_x509_ext(void) { @@ -295,7 +344,9 @@ WOLFSSL_STACK* wolfSSL_sk_new_x509_ext(void) return sk; } -/* return 1 on success 0 on fail */ +/* This function does NOT return 1 on success. It returns 0 on fail, and the + * number of items in the stack upon success. This is for compatibility with + * OpenSSL. */ int wolfSSL_sk_X509_EXTENSION_push(WOLFSSL_STACK* sk,WOLFSSL_X509_EXTENSION* ext) { WOLFSSL_STACK* node; @@ -310,7 +361,7 @@ int wolfSSL_sk_X509_EXTENSION_push(WOLFSSL_STACK* sk,WOLFSSL_X509_EXTENSION* ext if (sk->data.ext == NULL) { sk->data.ext = ext; sk->num += 1; - return WOLFSSL_SUCCESS; + return (int)sk->num; } /* stack already has value(s) create a new node and add more */ @@ -330,7 +381,7 @@ int wolfSSL_sk_X509_EXTENSION_push(WOLFSSL_STACK* sk,WOLFSSL_X509_EXTENSION* ext sk->data.ext = ext; sk->num += 1; - return WOLFSSL_SUCCESS; + return (int)sk->num; } /* Free the structure for X509_EXTENSION stack @@ -1133,7 +1184,34 @@ int wolfSSL_X509_add_ext(WOLFSSL_X509 *x509, WOLFSSL_X509_EXTENSION *ext, int lo WOLFSSL_GENERAL_NAMES* gns = ext->ext_sk; while (gns) { WOLFSSL_GENERAL_NAME* gn = gns->data.gn; - if (!gn || !gn->d.ia5 || + if ((gn != NULL) && (gn->type == ASN_OTHER_TYPE)) { + char *buf = NULL; + int ret = 0; + word32 len = 0; + + len = SetOthername(gn->d.otherName, NULL); + if (len == WOLFSSL_FAILURE) { + return WOLFSSL_FAILURE; + } + + buf = (char*)XMALLOC(len, x509->heap, DYNAMIC_TYPE_X509_EXT); + if (buf == NULL) { + WOLFSSL_MSG("Couldn't allocate memory for othername"); + return WOLFSSL_FAILURE; + } + + /* SetOthername() cannot fail; already passed above. */ + SetOthername(gn->d.otherName, (byte*)buf); + + ret = wolfSSL_X509_add_altname_ex(x509, buf, len, + ASN_OTHER_TYPE); + XFREE(buf, x509->heap, DYNAMIC_TYPE_X509_EXT); + if (ret == WOLFSSL_FAILURE) { + WOLFSSL_MSG("wolfSSL_X509_add_altname_ex() failed"); + return WOLFSSL_FAILURE; + } + } + else if (!gn || !gn->d.ia5 || wolfSSL_X509_add_altname_ex(x509, gn->d.ia5->data, gn->d.ia5->length, gn->type) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("Subject alternative name missing extension"); @@ -1163,8 +1241,54 @@ int wolfSSL_X509_add_ext(WOLFSSL_X509 *x509, WOLFSSL_X509_EXTENSION *ext, int lo } break; default: +#ifdef WOLFSSL_CUSTOM_OID + if ((ext->obj == NULL) || (ext->value.length == 0)) { + WOLFSSL_MSG("Extension has insufficient information."); + return WOLFSSL_FAILURE; + } + + if ((x509->customExtCount < 0) || + (x509->customExtCount >= NUM_CUSTOM_EXT)) { + WOLFSSL_MSG("Bad value for customExtCount."); + return WOLFSSL_FAILURE; + } + + /* This is a viable custom extension. */ + char *oid = XMALLOC(MAX_OID_STRING_SZ, x509->heap, + DYNAMIC_TYPE_X509_EXT); + byte *val = XMALLOC(ext->value.length, x509->heap, + DYNAMIC_TYPE_X509_EXT); + int err = 0; + + if ((oid == NULL) || (val == NULL)) { + WOLFSSL_MSG("Memory allocation failure.\n"); + err = 1; + } + + if (err == 0) { + XMEMCPY(val, ext->value.data, ext->value.length); + if (wolfSSL_OBJ_obj2txt(oid, MAX_OID_STRING_SZ, ext->obj, 1) < 0) { + err = 1; + } + } + + if (err == 1) { + XFREE(val, x509->heap, DYNAMIC_TYPE_X509_EXT); + XFREE(oid, x509->heap, DYNAMIC_TYPE_X509_EXT); + return WOLFSSL_FAILURE; + } + + /* x509->custom_exts now owns the buffers and they must be managed. */ + x509->custom_exts[x509->customExtCount].oid = oid; + x509->custom_exts[x509->customExtCount].crit = ext->crit; + x509->custom_exts[x509->customExtCount].val = val; + x509->custom_exts[x509->customExtCount].valSz = ext->value.length; + x509->customExtCount++; +#else WOLFSSL_MSG("Unsupported extension to add"); return WOLFSSL_FAILURE; +#endif /* WOLFSSL_CUSTOM_OID */ + break; } return WOLFSSL_SUCCESS; @@ -2697,6 +2821,12 @@ WOLFSSL_X509_EXTENSION *wolfSSL_X509V3_EXT_i2d(int nid, int crit, WOLFSSL_MSG("wolfSSL_sk_dup failed"); goto err_cleanup; } + + if (!(ext->obj = wolfSSL_OBJ_nid2obj(nid))) { + WOLFSSL_MSG("wolfSSL_ASN1_OBJECT_new failed"); + goto err_cleanup; + } + break; } case NID_basic_constraints: @@ -3343,6 +3473,7 @@ WOLFSSL_X509* wolfSSL_X509_REQ_d2i(WOLFSSL_X509** x509, return d2i_X509orX509REQ(x509, in, len, 1); } #endif + #endif /* KEEP_PEER_CERT || SESSION_CERTS || OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ @@ -4005,6 +4136,7 @@ WOLFSSL_GENERAL_NAME* wolfSSL_GENERAL_NAME_new(void) wolfSSL_GENERAL_NAME_free(gn); return NULL; } + gn->type = GEN_IA5; return gn; } @@ -4024,6 +4156,8 @@ WOLFSSL_GENERAL_NAME* wolfSSL_GENERAL_NAME_dup(WOLFSSL_GENERAL_NAME* gn) return NULL; } + wolfSSL_ASN1_STRING_free(dupl->d.ia5); + dupl->d.ia5 = NULL; switch (gn->type) { /* WOLFSSL_ASN1_STRING types */ case GEN_DNS: @@ -4052,6 +4186,37 @@ WOLFSSL_GENERAL_NAME* wolfSSL_GENERAL_NAME_dup(WOLFSSL_GENERAL_NAME* gn) } break; case GEN_OTHERNAME: + if (gn->d.otherName->value->type != V_ASN1_UTF8STRING) { + WOLFSSL_MSG("Unsupported othername value type"); + goto error; + } + dupl->d.otherName = (WOLFSSL_ASN1_OTHERNAME*)XMALLOC( + sizeof(WOLFSSL_ASN1_OTHERNAME), NULL, DYNAMIC_TYPE_ASN1); + if (dupl->d.otherName == NULL) { + WOLFSSL_MSG("XMALLOC error"); + goto error; + } + dupl->d.otherName->type_id = wolfSSL_ASN1_OBJECT_dup( + gn->d.otherName->type_id); + dupl->d.otherName->value = (WOLFSSL_ASN1_TYPE*)XMALLOC( + sizeof(WOLFSSL_ASN1_TYPE), NULL, DYNAMIC_TYPE_ASN1); + if (dupl->d.otherName->value != NULL) { + dupl->d.otherName->value->type = gn->d.otherName->value->type; + dupl->d.otherName->value->value.utf8string = + wolfSSL_ASN1_STRING_dup( + gn->d.otherName->value->value.utf8string); + } + if ((dupl->d.otherName->type_id == NULL) || + (dupl->d.otherName->value == NULL) || + (dupl->d.otherName->value->value.utf8string == NULL)) { + wolfSSL_ASN1_OBJECT_free(dupl->d.otherName->type_id); + wolfSSL_ASN1_TYPE_free(dupl->d.otherName->value); + XFREE(dupl->d.otherName, NULL, DYNAMIC_TYPE_ASN1); + dupl->d.otherName = NULL; + WOLFSSL_MSG("error duping othername"); + goto error; + } + break; case GEN_X400: case GEN_DIRNAME: case GEN_EDIPARTY: @@ -4070,6 +4235,33 @@ error: return NULL; } +/* Set an Othername in a general name. + * + * @param [out] gen Pointer to the GENERAL_NAME where the othername is set. + * @param [in] oid Object ID (ie UPN). + * @param [in] name The actual name. + * @return WOLFSSL_FAILURE on invalid parameter or memory error, + * WOLFSSL_SUCCESS otherwise. + */ +int wolfSSL_GENERAL_NAME_set0_othername(GENERAL_NAME* gen, ASN1_OBJECT* oid, + ASN1_TYPE* value) { + WOLFSSL_ASN1_OBJECT *x = NULL; + + if ((gen == NULL) || (oid == NULL) || (value == NULL)) { + return WOLFSSL_FAILURE; + } + + x = wolfSSL_ASN1_OBJECT_dup(oid); + if (x == NULL) { + WOLFSSL_MSG("wolfSSL_ASN1_OBJECT_dup() failed"); + return WOLFSSL_FAILURE; + } + + gen->type = GEN_OTHERNAME; + gen->d.otherName->type_id = x; + gen->d.otherName->value = value; + return WOLFSSL_SUCCESS; +} /* return 1 on success 0 on fail */ int wolfSSL_sk_GENERAL_NAME_push(WOLFSSL_GENERAL_NAMES* sk, @@ -4153,6 +4345,19 @@ int wolfSSL_sk_GENERAL_NAME_num(WOLFSSL_STACK* sk) return (int)sk->num; } +/* Allocates an empty GENERAL NAME stack */ +WOLFSSL_STACK* wolfSSL_sk_GENERAL_NAME_new(void *cmpFunc) { + WOLFSSL_STACK* sk = NULL; + (void)cmpFunc; + WOLFSSL_ENTER("wolfSSL_sk_GENERAL_NAME_new"); + + sk = wolfSSL_sk_new_null(); + if (sk != NULL) { + sk->type = STACK_TYPE_GEN_NAME; + } + + return sk; +} #endif /* OPENSSL_EXTRA */ #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) @@ -4363,34 +4568,52 @@ WOLFSSL_ACCESS_DESCRIPTION* wolfSSL_sk_ACCESS_DESCRIPTION_value( static void wolfSSL_GENERAL_NAME_type_free(WOLFSSL_GENERAL_NAME* name) { if (name != NULL) { - if (name->d.dNSName != NULL) { - wolfSSL_ASN1_STRING_free(name->d.dNSName); - name->d.dNSName = NULL; - } - if (name->d.dirn != NULL) { - wolfSSL_X509_NAME_free(name->d.dirn); - name->d.dirn = NULL; - } - if (name->d.uniformResourceIdentifier != NULL) { - wolfSSL_ASN1_STRING_free(name->d.uniformResourceIdentifier); - name->d.uniformResourceIdentifier = NULL; - } - if (name->d.iPAddress != NULL) { - wolfSSL_ASN1_STRING_free(name->d.iPAddress); - name->d.iPAddress = NULL; - } - if (name->d.registeredID != NULL) { - wolfSSL_ASN1_OBJECT_free(name->d.registeredID); - name->d.registeredID = NULL; - } - if (name->d.ia5 != NULL) { + switch (name->type) { + case GEN_IA5: wolfSSL_ASN1_STRING_free(name->d.ia5); name->d.ia5 = NULL; + break; + case GEN_EMAIL: + wolfSSL_ASN1_STRING_free(name->d.rfc822Name); + name->d.rfc822Name = NULL; + break; + case GEN_DNS: + wolfSSL_ASN1_STRING_free(name->d.dNSName); + name->d.dNSName = NULL; + break; + case GEN_DIRNAME: + wolfSSL_X509_NAME_free(name->d.dirn); + name->d.dirn = NULL; + break; + case GEN_URI: + wolfSSL_ASN1_STRING_free(name->d.uniformResourceIdentifier); + name->d.uniformResourceIdentifier = NULL; + break; + case GEN_IPADD: + wolfSSL_ASN1_STRING_free(name->d.iPAddress); + name->d.iPAddress = NULL; + break; + case GEN_RID: + wolfSSL_ASN1_OBJECT_free(name->d.registeredID); + name->d.registeredID = NULL; + break; + case GEN_OTHERNAME: + wolfSSL_ASN1_OBJECT_free(name->d.otherName->type_id); + wolfSSL_ASN1_TYPE_free(name->d.otherName->value); + XFREE(name->d.otherName, NULL, DYNAMIC_TYPE_ASN1); + name->d.otherName = NULL; + break; + case GEN_X400: + /* Unsupported: fall through */ + case GEN_EDIPARTY: + /* Unsupported: fall through */ + default: + WOLFSSL_MSG("wolfSSL_GENERAL_NAME_type_free: possible leak"); + break; } } } - /* sets the general name type and free's the existing one * can fail with a memory error if malloc fails or bad arg error * otherwise return WOLFSSL_SUCCESS */ @@ -4409,6 +4632,7 @@ int wolfSSL_GENERAL_NAME_set_type(WOLFSSL_GENERAL_NAME* name, int typ) ret = MEMORY_E; break; default: + name->type = GEN_IA5; name->d.ia5 = wolfSSL_ASN1_STRING_new(); if (name->d.ia5 == NULL) ret = MEMORY_E; @@ -7211,6 +7435,11 @@ static void *wolfSSL_d2i_X509_fp_ex(XFILE file, void **x509, int type) newx509 = (void *)wolfSSL_d2i_X509_CRL(NULL, fileBuffer, (int)sz); } #endif + #ifdef WOLFSSL_CERT_REQ + else if (type == CERTREQ_TYPE) { + newx509 = (void *)wolfSSL_X509_REQ_d2i(NULL, fileBuffer, (int)sz); + } + #endif #if !defined(NO_ASN) && !defined(NO_PWDBASED) && defined(HAVE_PKCS12) else if (type == PKCS12_TYPE) { if ((newx509 = wc_PKCS12_new()) == NULL) { @@ -7249,11 +7478,20 @@ _exit: return newx509; } +#ifdef WOLFSSL_CERT_REQ +WOLFSSL_X509* wolfSSL_d2i_X509_REQ_fp(XFILE fp, WOLFSSL_X509 **req) +{ + return (WOLFSSL_X509 *)wolfSSL_d2i_X509_fp_ex(fp, (void **)req, + CERTREQ_TYPE); +} +#endif /* WOLFSSL_CERT_REQ */ + WOLFSSL_X509 *wolfSSL_d2i_X509_fp(XFILE fp, WOLFSSL_X509 **x509) { WOLFSSL_ENTER("wolfSSL_d2i_X509_fp"); return (WOLFSSL_X509 *)wolfSSL_d2i_X509_fp_ex(fp, (void **)x509, CERT_TYPE); } + /* load certificate or CRL file, and add it to the STORE */ /* @param ctx a pointer to X509_LOOKUP structure */ /* @param file file name to load */ @@ -9228,11 +9466,33 @@ WOLF_STACK_OF(WOLFSSL_X509)* wolfSSL_X509_chain_up_ref( } } } + + #ifdef WOLFSSL_CUSTOM_OID + if (ret == WOLFSSL_SUCCESS) { + if ((req->customExtCount < 0) || + (req->customExtCount >= NUM_CUSTOM_EXT)) { + WOLFSSL_MSG("Bad value for customExtCount."); + ret = WOLFSSL_FAILURE; + } + + if (ret == WOLFSSL_SUCCESS) { + for (idx = 0; idx < req->customExtCount; idx++) { + /* Note that ownership is NOT transfered. + * req->custom_exts buffers still need to be cleaned + * up. */ + cert->customCertExt[idx] = req->custom_exts[idx]; + } + cert->customCertExtCount = req->customExtCount; + } + } + #endif /* WOLFSSL_CUSTOM_OID */ #endif /* OPENSSL_ALL */ #ifdef WOLFSSL_ALT_NAMES - cert->altNamesSz = FlattenAltNames(cert->altNames, - sizeof(cert->altNames), req->altNames); + if (ret == WOLFSSL_SUCCESS) { + cert->altNamesSz = FlattenAltNames(cert->altNames, + sizeof(cert->altNames), req->altNames); + } #endif /* WOLFSSL_ALT_NAMES */ } diff --git a/tests/api.c b/tests/api.c index 1e31ed641..6aafc64d7 100644 --- a/tests/api.c +++ b/tests/api.c @@ -43264,6 +43264,142 @@ static int test_wolfSSL_X509_NAME_ENTRY(void) return res; } +/* Note the lack of wolfSSL_ prefix...this is a compatability layer test. */ +static int test_GENERAL_NAME_set0_othername(void) { + int res = TEST_SKIPPED; +#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && \ + defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_REQ) && \ + defined(WOLFSSL_CUSTOM_OID) && defined(WOLFSSL_ALT_NAMES) && \ + defined(WOLFSSL_CERT_EXT) && !defined(NO_FILESYSTEM) + const char * cert_fname = "./certs/server-cert.der"; + const char * key_fname = "./certs/server-key.der"; + X509* x509 = NULL; + GENERAL_NAME* gn = NULL; + GENERAL_NAMES* gns = NULL; + ASN1_OBJECT* upn_oid = NULL; + ASN1_UTF8STRING *utf8str = NULL; + ASN1_TYPE *value = NULL; + X509_EXTENSION * ext = NULL; + + byte* pt = NULL; + byte der[4096]; + int derSz = 0; + EVP_PKEY* priv = NULL; + FILE* f = NULL; + + AssertNotNull(f = fopen(cert_fname, "rb")); + AssertNotNull(x509 = d2i_X509_fp(f, NULL)); + fclose(f); + AssertNotNull(gn = GENERAL_NAME_new()); + AssertNotNull(upn_oid = OBJ_txt2obj("1.3.6.1.4.1.311.20.2.3", 1)); + AssertNotNull(utf8str = ASN1_UTF8STRING_new()); + AssertIntEQ(ASN1_STRING_set(utf8str, "othername@wolfssl.com", -1), 1); + AssertNotNull(value = ASN1_TYPE_new()); + ASN1_TYPE_set(value, V_ASN1_UTF8STRING, utf8str); + AssertIntEQ(GENERAL_NAME_set0_othername(gn, upn_oid, value), 1); + AssertNotNull(gns = sk_GENERAL_NAME_new(NULL)); + AssertIntEQ(sk_GENERAL_NAME_push(gns, gn), 1); + AssertNotNull(ext = X509V3_EXT_i2d(NID_subject_alt_name, 0, gns)); + AssertIntEQ(X509_add_ext(x509, ext, -1), 1); + AssertNotNull(f = fopen(key_fname, "rb")); + AssertIntGT(derSz = (int)fread(der, 1, sizeof(der), f), 0); + fclose(f); + pt = der; + AssertNotNull(priv = d2i_PrivateKey(EVP_PKEY_RSA, NULL, + (const unsigned char**)&pt, derSz)); + AssertIntGT(X509_sign(x509, priv, EVP_sha256()), 0); + sk_GENERAL_NAME_pop_free(gns, GENERAL_NAME_free); + ASN1_OBJECT_free(upn_oid); + X509_EXTENSION_free(ext); + X509_free(x509); + EVP_PKEY_free(priv); + res = TEST_RES_CHECK(1); +#endif + return res; +} + +/* Note the lack of wolfSSL_ prefix...this is a compatability layer test. */ +static int test_othername_and_SID_ext(void) { + int res = TEST_SKIPPED; +#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && \ + defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_REQ) && \ + defined(WOLFSSL_CUSTOM_OID) && defined(WOLFSSL_ALT_NAMES) && \ + defined(WOLFSSL_CERT_EXT) && !defined(NO_FILESYSTEM) + + const char* csr_fname = "./certs/csr.signed.der"; + const char* key_fname = "./certs/server-key.der"; + + byte der[4096]; + int derSz = 0; + X509_REQ* x509 = NULL; + STACK_OF(X509_EXTENSION) *exts = NULL; + + X509_EXTENSION * san_ext = NULL; + GENERAL_NAME* gn = NULL; + GENERAL_NAMES* gns = NULL; + ASN1_OBJECT* upn_oid = NULL; + ASN1_UTF8STRING *utf8str = NULL; + ASN1_TYPE *value = NULL; + + /* SID extension. SID data format explained here: + * https://blog.qdsecurity.se/2022/05/27/manually-injecting-a-sid-in-a-certificate/ + */ + uint8_t SidExtension[] = { + 48, 64, 160, 62, 6, 10, 43, 6, 1, 4, 1, 130, 55, 25, 2, 1, 160, + 48, 4, 46, 83, 45, 49, 45, 53, 45, 50, 49, 45, 50, 56, 52, 51, 57, + 48, 55, 52, 49, 56, 45, 51, 57, 50, 54, 50, 55, 55, 52, 50, 49, 45, + 51, 56, 49, 53, 57, 57, 51, 57, 55, 50, 45, 52, 54, 48, 49}; + X509_EXTENSION *sid_ext = NULL; + ASN1_OBJECT* sid_oid = NULL; + ASN1_OCTET_STRING *sid_data = NULL; + + EVP_PKEY* priv = NULL; + FILE* f = NULL; + byte* pt = NULL; + + AssertNotNull(f = fopen(csr_fname, "rb")); + AssertNotNull(x509 = d2i_X509_REQ_fp(f, NULL)); + fclose(f); + AssertIntEQ(X509_REQ_set_version(x509, 2), 1); + AssertNotNull(gn = GENERAL_NAME_new()); + AssertNotNull(upn_oid = OBJ_txt2obj("1.3.6.1.4.1.311.20.2.3", 1)); + AssertNotNull(utf8str = ASN1_UTF8STRING_new()); + AssertIntEQ(ASN1_STRING_set(utf8str, "othername@wolfssl.com", -1), 1); + AssertNotNull(value = ASN1_TYPE_new()); + ASN1_TYPE_set(value, V_ASN1_UTF8STRING, utf8str); + AssertIntEQ(GENERAL_NAME_set0_othername(gn, upn_oid, value), 1); + AssertNotNull(gns = sk_GENERAL_NAME_new(NULL)); + AssertIntEQ(sk_GENERAL_NAME_push(gns, gn), 1); + AssertNotNull(san_ext = X509V3_EXT_i2d(NID_subject_alt_name, 0, gns)); + AssertNotNull(sid_oid = OBJ_txt2obj("1.3.6.1.4.1.311.25.2", 1)); + AssertNotNull(sid_data = ASN1_OCTET_STRING_new()); + ASN1_OCTET_STRING_set(sid_data, SidExtension, sizeof(SidExtension)); + AssertNotNull(sid_ext = X509_EXTENSION_create_by_OBJ(NULL, sid_oid, 0, + sid_data)); + AssertNotNull(exts = sk_X509_EXTENSION_new_null()); + AssertIntEQ(sk_X509_EXTENSION_push(exts, san_ext), 1); + AssertIntEQ(sk_X509_EXTENSION_push(exts, sid_ext), 2); + AssertIntEQ(X509_REQ_add_extensions(x509, exts), 1); + AssertNotNull(f = fopen(key_fname, "rb")); + AssertIntGT(derSz = (int)fread(der, 1, sizeof(der), f), 0); + fclose(f); + pt = der; + AssertNotNull(priv = d2i_PrivateKey(EVP_PKEY_RSA, NULL, + (const unsigned char**)&pt, derSz)); + AssertIntGT(X509_REQ_sign(x509, priv, EVP_sha256()), 0); + pt = der; + AssertIntGT(derSz = i2d_X509_REQ(x509, &pt), 0); + sk_GENERAL_NAME_pop_free(gns, GENERAL_NAME_free); + sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); + ASN1_OBJECT_free(upn_oid); + ASN1_OBJECT_free(sid_oid); + ASN1_OCTET_STRING_free(sid_data); + X509_REQ_free(x509); + EVP_PKEY_free(priv); + res = TEST_RES_CHECK(1); +#endif + return res; +} static int test_wolfSSL_X509_set_name(void) { @@ -45135,7 +45271,6 @@ static int test_wolfSSL_GENERAL_NAME_print(void) const char* x400Str = "X400Name:"; const char* ediStr = "EdiPartyName:"; - /* BIO to output */ AssertNotNull(out = BIO_new(BIO_s_mem())); @@ -45261,6 +45396,8 @@ static int test_wolfSSL_GENERAL_NAME_print(void) AssertIntGT(BIO_read(out, outbuf, sizeof(outbuf)), 0); AssertIntEQ(XSTRNCMP((const char*)outbuf, x400Str, XSTRLEN(x400Str)), 0); + /* Restore to GEN_IA5 (default) to avoid memory leak. */ + gn->type = GEN_IA5; GENERAL_NAME_free(gn); /* test for GEN_EDIPARTY */ @@ -45273,6 +45410,8 @@ static int test_wolfSSL_GENERAL_NAME_print(void) AssertIntGT(BIO_read(out, outbuf, sizeof(outbuf)), 0); AssertIntEQ(XSTRNCMP((const char*)outbuf, ediStr, XSTRLEN(ediStr)), 0); + /* Restore to GEN_IA5 (default) to avoid memory leak. */ + gn->type = GEN_IA5; GENERAL_NAME_free(gn); BIO_free(out); @@ -65153,6 +65292,8 @@ TEST_CASE testCases[] = { TEST_DECL(test_wolfSSL_OBJ_txt2obj), TEST_DECL(test_wolfSSL_PEM_write_bio_X509), TEST_DECL(test_wolfSSL_X509_NAME_ENTRY), + TEST_DECL(test_GENERAL_NAME_set0_othername), + TEST_DECL(test_othername_and_SID_ext), TEST_DECL(test_wolfSSL_X509_set_name), TEST_DECL(test_wolfSSL_X509_set_notAfter), TEST_DECL(test_wolfSSL_X509_set_notBefore), diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 28745f407..440976c0b 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -14574,6 +14574,49 @@ word32 SetExplicit(byte number, word32 len, byte* output) output); } +#if defined(OPENSSL_EXTRA) +/* Encode an Othername into DER. + * + * @param [in] name Pointer to the WOLFSSL_ASN1_OTHERNAME to be encoded. + * @param [out] output Buffer to encode into. If NULL, don't encode. + * @return Number of bytes encoded or WOLFSSL_FAILURE if name parameter is bad. + */ +word32 SetOthername(void *name, byte *output) +{ + WOLFSSL_ASN1_OTHERNAME *nm = (WOLFSSL_ASN1_OTHERNAME *)name; + char *nameStr = NULL; + int nameSz = 0; + word32 len = 0; + + if ((nm == NULL) || (nm->value == NULL)) { + WOLFSSL_MSG("otherName value is NULL"); + return WOLFSSL_FAILURE; + } + + nameStr = nm->value->value.utf8string->data; + nameSz = nm->value->value.utf8string->length; + + len = nm->type_id->objSz + + SetHeader(ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC, nameSz + 2, NULL) + + SetHeader(CTC_UTF8, nameSz, NULL) + nameSz; + + if (output != NULL) { + /* otherName OID */ + XMEMCPY(output, nm->type_id->obj, nm->type_id->objSz); + output += nm->type_id->objSz; + + output += SetHeader(ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC, nameSz + 2, + output); + + output += SetHeader(CTC_UTF8, nameSz, output); + + XMEMCPY(output, nameStr, nameSz); + output += nameSz; + } + + return len; +} +#endif /* OPENSSL_EXTRA */ #if defined(HAVE_ECC) && defined(HAVE_ECC_KEY_EXPORT) @@ -25949,7 +25992,7 @@ int FlattenAltNames(byte* output, word32 outputSz, const DNS_entry* names) i = idx; #endif output[idx] = (byte) (ASN_CONTEXT_SPECIFIC | curName->type); - if (curName->type == ASN_DIR_TYPE) { + if (curName->type == ASN_DIR_TYPE || curName->type == ASN_OTHER_TYPE) { output[idx] |= ASN_CONSTRUCTED; } idx++; diff --git a/wolfssl/internal.h b/wolfssl/internal.h index cb45d54f9..89bf9a46f 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -4802,6 +4802,10 @@ struct WOLFSSL_X509 { byte authKeyIdSet:1; byte authKeyIdCrit:1; byte issuerSet:1; +#ifdef WOLFSSL_CUSTOM_OID + CertExtension custom_exts[NUM_CUSTOM_EXT]; + int customExtCount; +#endif /* WOLFSSL_CUSTOM_OID */ #endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ #ifdef WOLFSSL_CERT_REQ byte isCSR:1; diff --git a/wolfssl/openssl/asn1.h b/wolfssl/openssl/asn1.h index 66fd41f35..edfa66291 100644 --- a/wolfssl/openssl/asn1.h +++ b/wolfssl/openssl/asn1.h @@ -185,5 +185,7 @@ WOLFSSL_API int wolfSSL_ASN1_item_i2d(const void *src, byte **dest, #define BN_to_ASN1_INTEGER wolfSSL_BN_to_ASN1_INTEGER #define ASN1_TYPE_set wolfSSL_ASN1_TYPE_set +#define ASN1_TYPE_new wolfSSL_ASN1_TYPE_new +#define ASN1_TYPE_free wolfSSL_ASN1_TYPE_free #endif /* WOLFSSL_ASN1_H_ */ diff --git a/wolfssl/openssl/ssl.h b/wolfssl/openssl/ssl.h index cc31f21d0..815759081 100644 --- a/wolfssl/openssl/ssl.h +++ b/wolfssl/openssl/ssl.h @@ -110,7 +110,7 @@ typedef WOLFSSL_ASN1_BIT_STRING ASN1_BIT_STRING; typedef WOLFSSL_dynlock_value CRYPTO_dynlock_value; typedef WOLFSSL_BUF_MEM BUF_MEM; typedef WOLFSSL_GENERAL_NAMES GENERAL_NAMES; -typedef WOLFSSL_GENERAL_NAME GENERAL_NAME; +typedef WOLFSSL_GENERAL_NAME GENERAL_NAME; typedef WOLFSSL_OBJ_NAME OBJ_NAME; typedef WOLFSSL_DIST_POINT_NAME DIST_POINT_NAME; typedef WOLFSSL_DIST_POINT DIST_POINT; @@ -392,16 +392,17 @@ typedef STACK_OF(ACCESS_DESCRIPTION) AUTHORITY_INFO_ACCESS; #define SSL_SESSION_get_max_early_data wolfSSL_SESSION_get_max_early_data #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) - #define SSL_MODE_RELEASE_BUFFERS 0x00000010U - #define ASN1_BOOLEAN WOLFSSL_ASN1_BOOLEAN - #define X509_get_ext wolfSSL_X509_get_ext - #define X509_get_ext_by_OBJ wolfSSL_X509_get_ext_by_OBJ - #define X509_cmp wolfSSL_X509_cmp - #define X509_EXTENSION_get_object wolfSSL_X509_EXTENSION_get_object - #define X509_EXTENSION_get_critical wolfSSL_X509_EXTENSION_get_critical - #define X509_EXTENSION_get_data wolfSSL_X509_EXTENSION_get_data - #define X509_EXTENSION_new wolfSSL_X509_EXTENSION_new - #define X509_EXTENSION_free wolfSSL_X509_EXTENSION_free + #define SSL_MODE_RELEASE_BUFFERS 0x00000010U + #define ASN1_BOOLEAN WOLFSSL_ASN1_BOOLEAN + #define X509_get_ext wolfSSL_X509_get_ext + #define X509_get_ext_by_OBJ wolfSSL_X509_get_ext_by_OBJ + #define X509_cmp wolfSSL_X509_cmp + #define X509_EXTENSION_get_object wolfSSL_X509_EXTENSION_get_object + #define X509_EXTENSION_get_critical wolfSSL_X509_EXTENSION_get_critical + #define X509_EXTENSION_get_data wolfSSL_X509_EXTENSION_get_data + #define X509_EXTENSION_new wolfSSL_X509_EXTENSION_new + #define X509_EXTENSION_free wolfSSL_X509_EXTENSION_free + #define X509_EXTENSION_create_by_OBJ wolfSSL_X509_EXTENSION_create_by_OBJ #endif #define DSA_dup_DH wolfSSL_DSA_dup_DH @@ -415,6 +416,7 @@ typedef STACK_OF(ACCESS_DESCRIPTION) AUTHORITY_INFO_ACCESS; #define i2d_X509_REQ_bio wolfSSL_i2d_X509_REQ_bio #define d2i_X509_bio wolfSSL_d2i_X509_bio #define d2i_X509_REQ_bio wolfSSL_d2i_X509_REQ_bio +#define d2i_X509_REQ_fp wolfSSL_d2i_X509_REQ_fp #define d2i_X509_fp wolfSSL_d2i_X509_fp #define i2d_X509 wolfSSL_i2d_X509 #define d2i_X509 wolfSSL_d2i_X509 @@ -878,6 +880,11 @@ wolfSSL_X509_STORE_set_verify_cb((WOLFSSL_X509_STORE *)(s), (WOLFSSL_X509_STORE_ #define ASN1_OCTET_STRING_free wolfSSL_ASN1_STRING_free #define ASN1_OCTET_STRING_set wolfSSL_ASN1_STRING_set +#define ASN1_UTF8STRING WOLFSSL_ASN1_STRING +#define ASN1_UTF8STRING_new wolfSSL_ASN1_STRING_new +#define ASN1_UTF8STRING_free wolfSSL_ASN1_STRING_free +#define ASN1_UTF8STRING_set wolfSSL_ASN1_STRING_set + #define ASN1_PRINTABLE_type(...) V_ASN1_PRINTABLESTRING #define ASN1_UTCTIME_pr wolfSSL_ASN1_UTCTIME_pr @@ -1345,6 +1352,7 @@ typedef WOLFSSL_SRTP_PROTECTION_PROFILE SRTP_PROTECTION_PROFILE; #define GENERAL_NAME_free wolfSSL_GENERAL_NAME_free #define GENERAL_NAME_dup wolfSSL_GENERAL_NAME_dup #define GENERAL_NAME_print wolfSSL_GENERAL_NAME_print +#define GENERAL_NAME_set0_othername wolfSSL_GENERAL_NAME_set0_othername #define sk_GENERAL_NAME_push wolfSSL_sk_GENERAL_NAME_push #define sk_GENERAL_NAME_value wolfSSL_sk_GENERAL_NAME_value @@ -1367,6 +1375,7 @@ typedef WOLFSSL_SRTP_PROTECTION_PROFILE SRTP_PROTECTION_PROFILE; #define SSL_SESSION_set1_id_context wolfSSL_SESSION_set1_id_context #define SSL_SESSION_print wolfSSL_SESSION_print #define sk_GENERAL_NAME_pop_free wolfSSL_sk_GENERAL_NAME_pop_free +#define sk_GENERAL_NAME_new wolfSSL_sk_GENERAL_NAME_new #define sk_GENERAL_NAME_free wolfSSL_sk_GENERAL_NAME_free #define sk_ASN1_OBJECT_pop_free wolfSSL_sk_ASN1_OBJECT_pop_free #define GENERAL_NAME_free wolfSSL_GENERAL_NAME_free diff --git a/wolfssl/openssl/x509v3.h b/wolfssl/openssl/x509v3.h index 09550edd5..30c953936 100644 --- a/wolfssl/openssl/x509v3.h +++ b/wolfssl/openssl/x509v3.h @@ -109,6 +109,7 @@ struct WOLFSSL_X509_EXTENSION { #define GEN_URI 6 #define GEN_IPADD 7 #define GEN_RID 8 +#define GEN_IA5 9 #define GENERAL_NAME WOLFSSL_GENERAL_NAME diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 15e952ae5..fe74ac944 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -1557,6 +1557,11 @@ WOLFSSL_API int wolfSSL_GENERAL_NAME_set_type(WOLFSSL_GENERAL_NAME* name, int typ); WOLFSSL_API WOLFSSL_GENERAL_NAMES* wolfSSL_GENERAL_NAMES_dup( WOLFSSL_GENERAL_NAMES* gns); +WOLFSSL_API int wolfSSL_GENERAL_NAME_set0_othername(WOLFSSL_GENERAL_NAME* gen, + WOLFSSL_ASN1_OBJECT* oid, + WOLFSSL_ASN1_TYPE* value); + +WOLFSSL_API WOLFSSL_STACK* wolfSSL_sk_GENERAL_NAME_new(void *cmpFunc); WOLFSSL_API int wolfSSL_sk_GENERAL_NAME_push(WOLFSSL_GENERAL_NAMES* sk, WOLFSSL_GENERAL_NAME* gn); WOLFSSL_API WOLFSSL_GENERAL_NAME* wolfSSL_sk_GENERAL_NAME_value( @@ -4279,6 +4284,9 @@ WOLFSSL_API int wolfSSL_X509_get_ext_by_OBJ(const WOLFSSL_X509 *x, WOLFSSL_API WOLFSSL_X509_EXTENSION* wolfSSL_X509_set_ext(WOLFSSL_X509* x, int loc); WOLFSSL_API int wolfSSL_X509_EXTENSION_get_critical(const WOLFSSL_X509_EXTENSION* ex); WOLFSSL_API WOLFSSL_X509_EXTENSION* wolfSSL_X509_EXTENSION_new(void); +WOLFSSL_API WOLFSSL_X509_EXTENSION* wolfSSL_X509_EXTENSION_create_by_OBJ( + WOLFSSL_X509_EXTENSION* ex, WOLFSSL_ASN1_OBJECT *obj, int crit, + WOLFSSL_ASN1_STRING *data); WOLFSSL_API WOLFSSL_X509_EXTENSION* wolfSSL_X509_EXTENSION_dup( WOLFSSL_X509_EXTENSION* src); WOLFSSL_API int wolfSSL_sk_X509_EXTENSION_push(WOLFSSL_STACK* sk, @@ -4316,6 +4324,9 @@ WOLFSSL_API WOLFSSL_X509* wolfSSL_d2i_X509_bio(WOLFSSL_BIO* bio, #ifdef WOLFSSL_CERT_REQ WOLFSSL_API WOLFSSL_X509* wolfSSL_d2i_X509_REQ_bio(WOLFSSL_BIO* bio, WOLFSSL_X509** x509); +#if !defined(NO_FILESYSTEM) +WOLFSSL_API WOLFSSL_X509* wolfSSL_d2i_X509_REQ_fp(XFILE fp, WOLFSSL_X509 **req); +#endif #endif #endif /* OPENSSL_EXTRA || OPENSSL_ALL */ diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index 5de97bd09..136318430 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -2166,6 +2166,9 @@ WOLFSSL_LOCAL word32 SetAlgoID(int algoOID,byte* output,int type,int curveSz); WOLFSSL_LOCAL int SetMyVersion(word32 version, byte* output, int header); WOLFSSL_LOCAL int SetSerialNumber(const byte* sn, word32 snSz, byte* output, word32 outputSz, int maxSnSz); +/* name is of type WOLFSSL_ASN1_OTHERNAME; use void* to avoid including ssl.h */ +WOLFSSL_LOCAL word32 SetOthername(void *name, byte *output); + #ifndef WOLFSSL_ASN_TEMPLATE WOLFSSL_LOCAL int wc_GetSerialNumber(const byte* input, word32* inOutIdx, byte* serial, int* serialSz, word32 maxIdx); diff --git a/wolfssl/wolfcrypt/asn_public.h b/wolfssl/wolfcrypt/asn_public.h index 0de6a2e6d..91b64323f 100644 --- a/wolfssl/wolfcrypt/asn_public.h +++ b/wolfssl/wolfcrypt/asn_public.h @@ -351,7 +351,6 @@ typedef struct NameAttrib { #endif /* WOLFSSL_MULTI_ATTRIB */ #endif /* WOLFSSL_CERT_GEN || OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ -#ifdef WOLFSSL_CERT_GEN #ifdef WOLFSSL_CUSTOM_OID typedef struct CertOidField { byte* oid; @@ -362,13 +361,12 @@ typedef struct CertOidField { } CertOidField; typedef struct CertExtension { - const char* oid; - byte crit; - const byte* val; - int valSz; + char* oid; + byte crit; + byte* val; + int valSz; } CertExtension; #endif -#endif /* WOLFSSL_CERT_GEN */ #if defined(WOLFSSL_CERT_GEN) || defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) typedef struct CertName { @@ -422,11 +420,8 @@ typedef struct CertName { } CertName; #endif /* WOLFSSL_CERT_GEN || OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL*/ -#ifdef WOLFSSL_CERT_GEN - #ifndef NUM_CUSTOM_EXT #define NUM_CUSTOM_EXT 16 -#endif /* for user to fill for certificate generation */ typedef struct Cert { @@ -434,10 +429,13 @@ typedef struct Cert { byte serial[CTC_SERIAL_SIZE]; /* serial number */ int serialSz; /* serial size */ int sigType; /* signature algo type */ +#if defined(WOLFSSL_CERT_GEN) || defined(OPENSSL_EXTRA) \ + || defined(OPENSSL_EXTRA_X509_SMALL) CertName issuer; /* issuer info */ + CertName subject; /* subject info */ +#endif /* WOLFSSL_CERT_GEN || OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ int daysValid; /* validity days */ int selfSigned; /* self signed flag */ - CertName subject; /* subject info */ int isCA; /* is this going to be a CA */ byte pathLen; /* max depth of valid certification * paths that include this cert */ @@ -492,7 +490,7 @@ typedef struct Cert { char challengePw[CTC_NAME_SIZE]; char unstructuredName[CTC_NAME_SIZE]; int challengePwPrintableString; /* encode as PrintableString */ -#endif +#endif /* WOLFSSL_CERT_REQ */ #ifdef WOLFSSL_CUSTOM_OID /* user oid and value to go in req extensions */ CertOidField extCustom; @@ -500,7 +498,7 @@ typedef struct Cert { /* Extensions to go into X.509 certificates */ CertExtension customCertExt[NUM_CUSTOM_EXT]; int customCertExtCount; -#endif +#endif /* WOLFSSL_CUSTOM_OID */ void* decodedCert; /* internal DecodedCert allocated from heap */ byte* der; /* Pointer to buffer of current DecodedCert cache */ void* heap; /* heap hint */