/*
- * Copyright 1999-2017 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1999-2020 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
#include "internal/cryptlib.h"
#include <openssl/conf.h>
#include <openssl/x509v3.h>
+#include <openssl/bio.h>
#include "ext_dat.h"
+DEFINE_STACK_OF(CONF_VALUE)
+DEFINE_STACK_OF(GENERAL_NAME)
+
static GENERAL_NAMES *v2i_subject_alt(X509V3_EXT_METHOD *method,
X509V3_CTX *ctx,
STACK_OF(CONF_VALUE) *nval);
{
int i;
GENERAL_NAME *gen;
+ STACK_OF(CONF_VALUE) *tmpret = NULL, *origret = ret;
+
for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
gen = sk_GENERAL_NAME_value(gens, i);
- ret = i2v_GENERAL_NAME(method, gen, ret);
+ /*
+ * i2v_GENERAL_NAME allocates ret if it is NULL. If something goes
+ * wrong we need to free the stack - but only if it was empty when we
+ * originally entered this function.
+ */
+ tmpret = i2v_GENERAL_NAME(method, gen, ret);
+ if (tmpret == NULL) {
+ if (origret == NULL)
+ sk_CONF_VALUE_pop_free(ret, X509V3_conf_free);
+ return NULL;
+ }
+ ret = tmpret;
}
- if (!ret)
+ if (ret == NULL)
return sk_CONF_VALUE_new_null();
return ret;
}
GENERAL_NAME *gen,
STACK_OF(CONF_VALUE) *ret)
{
- unsigned char *p;
- char oline[256], htmp[5];
- int i;
+ char othername[300];
+ char oline[256], *tmp;
switch (gen->type) {
case GEN_OTHERNAME:
- if (!X509V3_add_value("othername", "<unsupported>", &ret))
- return NULL;
+ switch (OBJ_obj2nid(gen->d.otherName->type_id)) {
+ case NID_id_on_SmtpUTF8Mailbox:
+ if (gen->d.otherName->value->type != V_ASN1_UTF8STRING
+ || !X509V3_add_value_uchar("othername: SmtpUTF8Mailbox:",
+ gen->d.otherName->value->value.utf8string->data,
+ &ret))
+ return NULL;
+ break;
+ case NID_XmppAddr:
+ if (gen->d.otherName->value->type != V_ASN1_UTF8STRING
+ || !X509V3_add_value_uchar("othername: XmppAddr:",
+ gen->d.otherName->value->value.utf8string->data,
+ &ret))
+ return NULL;
+ break;
+ case NID_SRVName:
+ if (gen->d.otherName->value->type != V_ASN1_IA5STRING
+ || !X509V3_add_value_uchar("othername: SRVName:",
+ gen->d.otherName->value->value.ia5string->data,
+ &ret))
+ return NULL;
+ break;
+ case NID_ms_upn:
+ if (gen->d.otherName->value->type != V_ASN1_UTF8STRING
+ || !X509V3_add_value_uchar("othername: UPN:",
+ gen->d.otherName->value->value.utf8string->data,
+ &ret))
+ return NULL;
+ break;
+ case NID_NAIRealm:
+ if (gen->d.otherName->value->type != V_ASN1_UTF8STRING
+ || !X509V3_add_value_uchar("othername: NAIRealm:",
+ gen->d.otherName->value->value.utf8string->data,
+ &ret))
+ return NULL;
+ break;
+ default:
+ if (OBJ_obj2txt(oline, sizeof(oline), gen->d.otherName->type_id, 0) > 0)
+ BIO_snprintf(othername, sizeof(othername), "othername: %s:",
+ oline);
+ else
+ OPENSSL_strlcpy(othername, "othername:", sizeof(othername));
+
+ /* check if the value is something printable */
+ if (gen->d.otherName->value->type == V_ASN1_IA5STRING) {
+ if (X509V3_add_value_uchar(othername,
+ gen->d.otherName->value->value.ia5string->data,
+ &ret))
+ return ret;
+ }
+ if (gen->d.otherName->value->type == V_ASN1_UTF8STRING) {
+ if (X509V3_add_value_uchar(othername,
+ gen->d.otherName->value->value.utf8string->data,
+ &ret))
+ return ret;
+ }
+ if (!X509V3_add_value(othername, "<unsupported>", &ret))
+ return NULL;
+ break;
+ }
break;
case GEN_X400:
break;
case GEN_IPADD:
- p = gen->d.ip->data;
- if (gen->d.ip->length == 4)
- BIO_snprintf(oline, sizeof(oline), "%d.%d.%d.%d",
- p[0], p[1], p[2], p[3]);
- else if (gen->d.ip->length == 16) {
- oline[0] = 0;
- for (i = 0; i < 8; i++) {
- BIO_snprintf(htmp, sizeof(htmp), "%X", p[0] << 8 | p[1]);
- p += 2;
- strcat(oline, htmp);
- if (i != 7)
- strcat(oline, ":");
- }
- } else {
- if (!X509V3_add_value("IP Address", "<invalid>", &ret))
- return NULL;
- break;
- }
- if (!X509V3_add_value("IP Address", oline, &ret))
- return NULL;
+ tmp = ipaddr_to_asc(gen->d.ip->data, gen->d.ip->length);
+ if (tmp == NULL || !X509V3_add_value("IP Address", tmp, &ret))
+ ret = NULL;
+ OPENSSL_free(tmp);
break;
case GEN_RID:
int GENERAL_NAME_print(BIO *out, GENERAL_NAME *gen)
{
- unsigned char *p;
- int i;
+ char *tmp;
+ int nid;
+
switch (gen->type) {
case GEN_OTHERNAME:
- BIO_printf(out, "othername:<unsupported>");
+ nid = OBJ_obj2nid(gen->d.otherName->type_id);
+ /* Validate the types are as we expect before we use them */
+ if ((nid == NID_SRVName
+ && gen->d.otherName->value->type != V_ASN1_IA5STRING)
+ || (nid != NID_SRVName
+ && gen->d.otherName->value->type != V_ASN1_UTF8STRING)) {
+ BIO_printf(out, "othername:<unsupported>");
+ break;
+ }
+
+ switch (nid) {
+ case NID_id_on_SmtpUTF8Mailbox:
+ BIO_printf(out, "othername:SmtpUTF8Mailbox:%s",
+ gen->d.otherName->value->value.utf8string->data);
+ break;
+ case NID_XmppAddr:
+ BIO_printf(out, "othername:XmppAddr:%s",
+ gen->d.otherName->value->value.utf8string->data);
+ break;
+ case NID_SRVName:
+ BIO_printf(out, "othername:SRVName:%s",
+ gen->d.otherName->value->value.ia5string->data);
+ break;
+ case NID_ms_upn:
+ BIO_printf(out, "othername:UPN:%s",
+ gen->d.otherName->value->value.utf8string->data);
+ break;
+ case NID_NAIRealm:
+ BIO_printf(out, "othername:NAIRealm:%s",
+ gen->d.otherName->value->value.utf8string->data);
+ break;
+ default:
+ BIO_printf(out, "othername:<unsupported>");
+ break;
+ }
break;
case GEN_X400:
break;
case GEN_IPADD:
- p = gen->d.ip->data;
- if (gen->d.ip->length == 4)
- BIO_printf(out, "IP Address:%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
- else if (gen->d.ip->length == 16) {
- BIO_printf(out, "IP Address");
- for (i = 0; i < 8; i++) {
- BIO_printf(out, ":%X", p[0] << 8 | p[1]);
- p += 2;
- }
- } else {
- BIO_printf(out, "IP Address:<invalid>");
- break;
- }
+ tmp = ipaddr_to_asc(gen->d.ip->data, gen->d.ip->length);
+ if (tmp == NULL)
+ return 0;
+ BIO_printf(out, "IP Address:%s", tmp);
+ OPENSSL_free(tmp);
break;
case GEN_RID:
for (i = 0; i < num; i++) {
CONF_VALUE *cnf = sk_CONF_VALUE_value(nval, i);
- if (!name_cmp(cnf->name, "issuer")
+ if (!v3_name_cmp(cnf->name, "issuer")
&& cnf->value && strcmp(cnf->value, "copy") == 0) {
if (!copy_issuer(ctx, gens))
goto err;
for (i = 0; i < num; i++) {
cnf = sk_CONF_VALUE_value(nval, i);
- if (!name_cmp(cnf->name, "email")
+ if (!v3_name_cmp(cnf->name, "email")
&& cnf->value && strcmp(cnf->value, "copy") == 0) {
if (!copy_email(ctx, gens, 0))
goto err;
- } else if (!name_cmp(cnf->name, "email")
+ } else if (!v3_name_cmp(cnf->name, "email")
&& cnf->value && strcmp(cnf->value, "move") == 0) {
if (!copy_email(ctx, gens, 1))
goto err;
return NULL;
}
- if (!name_cmp(name, "email"))
+ if (!v3_name_cmp(name, "email"))
type = GEN_EMAIL;
- else if (!name_cmp(name, "URI"))
+ else if (!v3_name_cmp(name, "URI"))
type = GEN_URI;
- else if (!name_cmp(name, "DNS"))
+ else if (!v3_name_cmp(name, "DNS"))
type = GEN_DNS;
- else if (!name_cmp(name, "RID"))
+ else if (!v3_name_cmp(name, "RID"))
type = GEN_RID;
- else if (!name_cmp(name, "IP"))
+ else if (!v3_name_cmp(name, "IP"))
type = GEN_IPADD;
- else if (!name_cmp(name, "dirName"))
+ else if (!v3_name_cmp(name, "dirName"))
type = GEN_DIRNAME;
- else if (!name_cmp(name, "otherName"))
+ else if (!v3_name_cmp(name, "otherName"))
type = GEN_OTHERNAME;
else {
X509V3err(X509V3_F_V2I_GENERAL_NAME_EX, X509V3_R_UNSUPPORTED_OPTION);