/*
- * Copyright 1999-2017 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1999-2022 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
/* X509 v3 extension utilities */
-#include "e_os.h"
+#include "internal/e_os.h"
#include "internal/cryptlib.h"
#include <stdio.h>
+#include <string.h>
#include "crypto/ctype.h"
#include <openssl/conf.h>
#include <openssl/crypto.h>
#include "crypto/x509.h"
#include <openssl/bn.h>
#include "ext_dat.h"
+#include "x509_local.h"
static char *strip_spaces(char *name);
static int sk_strcmp(const char *const *a, const char *const *b);
-static STACK_OF(OPENSSL_STRING) *get_email(X509_NAME *name,
+static STACK_OF(OPENSSL_STRING) *get_email(const X509_NAME *name,
GENERAL_NAMES *gens);
static void str_free(OPENSSL_STRING str);
-static int append_ia5(STACK_OF(OPENSSL_STRING) **sk, const ASN1_IA5STRING *email);
+static int append_ia5(STACK_OF(OPENSSL_STRING) **sk,
+ const ASN1_IA5STRING *email);
static int ipv4_from_asc(unsigned char *v4, const char *in);
static int ipv6_from_asc(unsigned char *v6, const char *in);
/* Add a CONF_VALUE name value pair to stack */
-int X509V3_add_value(const char *name, const char *value,
- STACK_OF(CONF_VALUE) **extlist)
+static int x509v3_add_len_value(const char *name, const char *value,
+ size_t vallen, STACK_OF(CONF_VALUE) **extlist)
{
CONF_VALUE *vtmp = NULL;
char *tname = NULL, *tvalue = NULL;
int sk_allocated = (*extlist == NULL);
- if (name && (tname = OPENSSL_strdup(name)) == NULL)
- goto err;
- if (value && (tvalue = OPENSSL_strdup(value)) == NULL)
+ if (name != NULL && (tname = OPENSSL_strdup(name)) == NULL)
goto err;
+ if (value != NULL) {
+ /* We don't allow embedded NUL characters */
+ if (memchr(value, 0, vallen) != NULL)
+ goto err;
+ tvalue = OPENSSL_strndup(value, vallen);
+ if (tvalue == NULL)
+ goto err;
+ }
if ((vtmp = OPENSSL_malloc(sizeof(*vtmp))) == NULL)
goto err;
- if (sk_allocated && (*extlist = sk_CONF_VALUE_new_null()) == NULL)
+ if (sk_allocated && (*extlist = sk_CONF_VALUE_new_null()) == NULL) {
+ ERR_raise(ERR_LIB_X509V3, ERR_R_CRYPTO_LIB);
goto err;
+ }
vtmp->section = NULL;
vtmp->name = tname;
vtmp->value = tvalue;
goto err;
return 1;
err:
- X509V3err(X509V3_F_X509V3_ADD_VALUE, ERR_R_MALLOC_FAILURE);
if (sk_allocated) {
sk_CONF_VALUE_free(*extlist);
*extlist = NULL;
return 0;
}
+int X509V3_add_value(const char *name, const char *value,
+ STACK_OF(CONF_VALUE) **extlist)
+{
+ return x509v3_add_len_value(name, value,
+ value != NULL ? strlen((const char *)value) : 0,
+ extlist);
+}
+
int X509V3_add_value_uchar(const char *name, const unsigned char *value,
STACK_OF(CONF_VALUE) **extlist)
{
- return X509V3_add_value(name, (const char *)value, extlist);
+ return x509v3_add_len_value(name, (const char *)value,
+ value != NULL ? strlen((const char *)value) : 0,
+ extlist);
+}
+
+int x509v3_add_len_value_uchar(const char *name, const unsigned char *value,
+ size_t vallen, STACK_OF(CONF_VALUE) **extlist)
+{
+ return x509v3_add_len_value(name, (const char *)value, vallen, extlist);
}
/* Free function for STACK_OF(CONF_VALUE) */
len = strlen(tmp) + 3;
ret = OPENSSL_malloc(len);
if (ret == NULL) {
- X509V3err(X509V3_F_BIGNUM_TO_STRING, ERR_R_MALLOC_FAILURE);
OPENSSL_free(tmp);
return NULL;
}
if (!a)
return NULL;
- if ((bntmp = ASN1_ENUMERATED_to_BN(a, NULL)) == NULL
- || (strtmp = bignum_to_string(bntmp)) == NULL)
- X509V3err(X509V3_F_I2S_ASN1_ENUMERATED, ERR_R_MALLOC_FAILURE);
+ if ((bntmp = ASN1_ENUMERATED_to_BN(a, NULL)) == NULL)
+ ERR_raise(ERR_LIB_X509V3, ERR_R_ASN1_LIB);
+ else if ((strtmp = bignum_to_string(bntmp)) == NULL)
+ ERR_raise(ERR_LIB_X509V3, ERR_R_X509V3_LIB);
BN_free(bntmp);
return strtmp;
}
if (!a)
return NULL;
- if ((bntmp = ASN1_INTEGER_to_BN(a, NULL)) == NULL
- || (strtmp = bignum_to_string(bntmp)) == NULL)
- X509V3err(X509V3_F_I2S_ASN1_INTEGER, ERR_R_MALLOC_FAILURE);
+ if ((bntmp = ASN1_INTEGER_to_BN(a, NULL)) == NULL)
+ ERR_raise(ERR_LIB_X509V3, ERR_R_ASN1_LIB);
+ else if ((strtmp = bignum_to_string(bntmp)) == NULL)
+ ERR_raise(ERR_LIB_X509V3, ERR_R_X509V3_LIB);
BN_free(bntmp);
return strtmp;
}
ASN1_INTEGER *aint;
int isneg, ishex;
int ret;
+
if (value == NULL) {
- X509V3err(X509V3_F_S2I_ASN1_INTEGER, X509V3_R_INVALID_NULL_VALUE);
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_NULL_VALUE);
return NULL;
}
bn = BN_new();
if (bn == NULL) {
- X509V3err(X509V3_F_S2I_ASN1_INTEGER, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_X509V3, ERR_R_BN_LIB);
return NULL;
}
if (value[0] == '-') {
value++;
isneg = 1;
- } else
+ } else {
isneg = 0;
+ }
if (value[0] == '0' && ((value[1] == 'x') || (value[1] == 'X'))) {
value += 2;
ishex = 1;
- } else
+ } else {
ishex = 0;
+ }
if (ishex)
ret = BN_hex2bn(&bn, value);
if (!ret || value[ret]) {
BN_free(bn);
- X509V3err(X509V3_F_S2I_ASN1_INTEGER, X509V3_R_BN_DEC2BN_ERROR);
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_BN_DEC2BN_ERROR);
return NULL;
}
aint = BN_to_ASN1_INTEGER(bn, NULL);
BN_free(bn);
if (!aint) {
- X509V3err(X509V3_F_S2I_ASN1_INTEGER,
- X509V3_R_BN_TO_ASN1_INTEGER_ERROR);
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_BN_TO_ASN1_INTEGER_ERROR);
return NULL;
}
if (isneg)
return 1;
}
err:
- X509V3err(X509V3_F_X509V3_GET_VALUE_BOOL,
- X509V3_R_INVALID_BOOLEAN_STRING);
- X509V3_conf_err(value);
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_BOOLEAN_STRING);
+ X509V3_conf_add_error_name_value(value);
return 0;
}
ASN1_INTEGER *itmp;
if ((itmp = s2i_ASN1_INTEGER(NULL, value->value)) == NULL) {
- X509V3_conf_err(value);
+ X509V3_conf_add_error_name_value(value);
return 0;
}
*aint = itmp;
STACK_OF(CONF_VALUE) *values = NULL;
char *linebuf;
int state;
+
/* We are going to modify the line so copy it first */
linebuf = OPENSSL_strdup(line);
- if (linebuf == NULL) {
- X509V3err(X509V3_F_X509V3_PARSE_LIST, ERR_R_MALLOC_FAILURE);
+ if (linebuf == NULL)
goto err;
- }
state = HDR_NAME;
ntmp = NULL;
/* Go through all characters */
*p = 0;
ntmp = strip_spaces(q);
if (!ntmp) {
- X509V3err(X509V3_F_X509V3_PARSE_LIST,
- X509V3_R_INVALID_NULL_NAME);
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_EMPTY_NAME);
goto err;
}
q = p + 1;
ntmp = strip_spaces(q);
q = p + 1;
if (!ntmp) {
- X509V3err(X509V3_F_X509V3_PARSE_LIST,
- X509V3_R_INVALID_NULL_NAME);
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_EMPTY_NAME);
+ goto err;
+ }
+ if (!X509V3_add_value(ntmp, NULL, &values)) {
goto err;
}
- X509V3_add_value(ntmp, NULL, &values);
}
break;
*p = 0;
vtmp = strip_spaces(q);
if (!vtmp) {
- X509V3err(X509V3_F_X509V3_PARSE_LIST,
- X509V3_R_INVALID_NULL_VALUE);
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_NULL_VALUE);
+ goto err;
+ }
+ if (!X509V3_add_value(ntmp, vtmp, &values)) {
goto err;
}
- X509V3_add_value(ntmp, vtmp, &values);
ntmp = NULL;
q = p + 1;
}
if (state == HDR_VALUE) {
vtmp = strip_spaces(q);
if (!vtmp) {
- X509V3err(X509V3_F_X509V3_PARSE_LIST,
- X509V3_R_INVALID_NULL_VALUE);
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_NULL_VALUE);
+ goto err;
+ }
+ if (!X509V3_add_value(ntmp, vtmp, &values)) {
goto err;
}
- X509V3_add_value(ntmp, vtmp, &values);
} else {
ntmp = strip_spaces(q);
if (!ntmp) {
- X509V3err(X509V3_F_X509V3_PARSE_LIST, X509V3_R_INVALID_NULL_NAME);
+ ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_EMPTY_NAME);
+ goto err;
+ }
+ if (!X509V3_add_value(ntmp, NULL, &values)) {
goto err;
}
- X509V3_add_value(ntmp, NULL, &values);
}
OPENSSL_free(linebuf);
return values;
static char *strip_spaces(char *name)
{
char *p, *q;
+
/* Skip over leading spaces */
p = name;
while (*p && ossl_isspace(*p))
* V2I name comparison function: returns zero if 'name' matches cmp or cmp.*
*/
-int name_cmp(const char *name, const char *cmp)
+int ossl_v3_name_cmp(const char *name, const char *cmp)
{
int len, ret;
char c;
+
len = strlen(cmp);
if ((ret = strncmp(name, cmp, len)))
return ret;
return ret;
}
-static STACK_OF(OPENSSL_STRING) *get_email(X509_NAME *name,
+static STACK_OF(OPENSSL_STRING) *get_email(const X509_NAME *name,
GENERAL_NAMES *gens)
{
STACK_OF(OPENSSL_STRING) *ret = NULL;
OPENSSL_free(str);
}
-static int append_ia5(STACK_OF(OPENSSL_STRING) **sk, const ASN1_IA5STRING *email)
+static int append_ia5(STACK_OF(OPENSSL_STRING) **sk,
+ const ASN1_IA5STRING *email)
{
char *emtmp;
+
/* First some sanity checks */
if (email->type != V_ASN1_IA5STRING)
return 1;
- if (!email->data || !email->length)
+ if (email->data == NULL || email->length == 0)
+ return 1;
+ if (memchr(email->data, 0, email->length) != NULL)
return 1;
if (*sk == NULL)
*sk = sk_OPENSSL_STRING_new(sk_strcmp);
if (*sk == NULL)
return 0;
+
+ emtmp = OPENSSL_strndup((char *)email->data, email->length);
+ if (emtmp == NULL) {
+ X509_email_free(*sk);
+ *sk = NULL;
+ return 0;
+ }
+
/* Don't add duplicates */
- if (sk_OPENSSL_STRING_find(*sk, (char *)email->data) != -1)
+ if (sk_OPENSSL_STRING_find(*sk, emtmp) != -1) {
+ OPENSSL_free(emtmp);
return 1;
- emtmp = OPENSSL_strdup((char *)email->data);
- if (emtmp == NULL || !sk_OPENSSL_STRING_push(*sk, emtmp)) {
- OPENSSL_free(emtmp); /* free on push failure */
+ }
+ if (!sk_OPENSSL_STRING_push(*sk, emtmp)) {
+ OPENSSL_free(emtmp); /* free on push failure */
X509_email_free(*sk);
*sk = NULL;
return 0;
skip_prefix(&pattern, &pattern_len, subject_len, flags);
if (pattern_len != subject_len)
return 0;
- while (pattern_len) {
+ while (pattern_len != 0) {
unsigned char l = *pattern;
unsigned char r = *subject;
+
/* The pattern must not contain NUL characters. */
if (l == 0)
return 0;
unsigned int unused_flags)
{
size_t i = a_len;
+
if (a_len != b_len)
return 0;
/*
}
/* IDNA labels cannot match partial wildcards */
if (!allow_idna &&
- subject_len >= 4 && strncasecmp((char *)subject, "xn--", 4) == 0)
+ subject_len >= 4 && HAS_CASE_PREFIX((const char *)subject, "xn--"))
return 0;
/* The wildcard may match a literal '*' */
if (wildcard_end == wildcard_start + 1 && *wildcard_start == '*')
size_t i;
int state = LABEL_START;
int dots = 0;
+
for (i = 0; i < len; ++i) {
/*
* Locate first and only legal wildcard, either at the start
|| ('A' <= p[i] && p[i] <= 'Z')
|| ('0' <= p[i] && p[i] <= '9')) {
if ((state & LABEL_START) != 0
- && len - i >= 4 && strncasecmp((char *)&p[i], "xn--", 4) == 0)
+ && len - i >= 4 && HAS_CASE_PREFIX((const char *)&p[i], "xn--"))
state |= LABEL_IDNA;
state &= ~(LABEL_HYPHEN | LABEL_START);
} else if (p[i] == '.') {
if ((state & LABEL_START) != 0)
return NULL;
state |= LABEL_HYPHEN;
- } else
+ } else {
return NULL;
+ }
}
/*
rv = equal(a->data, a->length, (unsigned char *)b, blen, flags);
else if (a->length == (int)blen && !memcmp(a->data, b, blen))
rv = 1;
- if (rv > 0 && peername)
+ if (rv > 0 && peername != NULL) {
*peername = OPENSSL_strndup((char *)a->data, a->length);
+ if (*peername == NULL)
+ return -1;
+ }
} else {
int astrlen;
unsigned char *astr;
return -1;
}
rv = equal(astr, astrlen, (unsigned char *)b, blen, flags);
- if (rv > 0 && peername)
+ if (rv > 0 && peername != NULL) {
*peername = OPENSSL_strndup((char *)astr, astrlen);
+ if (*peername == NULL) {
+ OPENSSL_free(astr);
+ return -1;
+ }
+ }
OPENSSL_free(astr);
}
return rv;
unsigned int flags, int check_type, char **peername)
{
GENERAL_NAMES *gens = NULL;
- X509_NAME *name = NULL;
+ const X509_NAME *name = NULL;
int i;
int cnid = NID_undef;
int alt_type;
for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
GENERAL_NAME *gen;
ASN1_STRING *cstr;
+
gen = sk_GENERAL_NAME_value(gens, i);
- if (gen->type != check_type)
- continue;
+ if ((gen->type == GEN_OTHERNAME) && (check_type == GEN_EMAIL)) {
+ if (OBJ_obj2nid(gen->d.otherName->type_id) ==
+ NID_id_on_SmtpUTF8Mailbox) {
+ san_present = 1;
+
+ /*
+ * If it is not a UTF8String then that is unexpected and we
+ * treat it as no match
+ */
+ if (gen->d.otherName->value->type == V_ASN1_UTF8STRING) {
+ cstr = gen->d.otherName->value->value.utf8string;
+
+ /* Positive on success, negative on error! */
+ if ((rv = do_check_string(cstr, 0, equal, flags,
+ chk, chklen, peername)) != 0)
+ break;
+ }
+ } else
+ continue;
+ } else {
+ if ((gen->type != check_type) && (gen->type != GEN_OTHERNAME))
+ continue;
+ }
san_present = 1;
if (check_type == GEN_EMAIL)
cstr = gen->d.rfc822Name;
if (ipasc == NULL)
return -2;
- iplen = (size_t)a2i_ipadd(ipout, ipasc);
+ iplen = (size_t)ossl_a2i_ipadd(ipout, ipasc);
if (iplen == 0)
return -2;
return do_x509_check(x, (char *)ipout, iplen, flags, GEN_IPADD, NULL);
}
+char *ossl_ipaddr_to_asc(unsigned char *p, int len)
+{
+ /*
+ * 40 is enough space for the longest IPv6 address + nul terminator byte
+ * XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX\0
+ */
+ char buf[40], *out;
+ int i = 0, remain = 0, bytes = 0;
+
+ switch (len) {
+ case 4: /* IPv4 */
+ BIO_snprintf(buf, sizeof(buf), "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
+ break;
+ case 16: /* IPv6 */
+ for (out = buf, i = 8, remain = sizeof(buf);
+ i-- > 0 && bytes >= 0;
+ remain -= bytes, out += bytes) {
+ const char *template = (i > 0 ? "%X:" : "%X");
+
+ bytes = BIO_snprintf(out, remain, template, p[0] << 8 | p[1]);
+ p += 2;
+ }
+ break;
+ default:
+ BIO_snprintf(buf, sizeof(buf), "<invalid length=%d>", len);
+ break;
+ }
+ return OPENSSL_strdup(buf);
+}
+
/*
* Convert IP addresses both IPv4 and IPv6 into an OCTET STRING compatible
* with RFC3280.
/* If string contains a ':' assume IPv6 */
- iplen = a2i_ipadd(ipout, ipasc);
+ iplen = ossl_a2i_ipadd(ipout, ipasc);
if (!iplen)
return NULL;
p = iptmp + (p - ipasc);
*p++ = 0;
- iplen1 = a2i_ipadd(ipout, iptmp);
+ iplen1 = ossl_a2i_ipadd(ipout, iptmp);
if (!iplen1)
goto err;
- iplen2 = a2i_ipadd(ipout + iplen1, p);
+ iplen2 = ossl_a2i_ipadd(ipout + iplen1, p);
OPENSSL_free(iptmp);
iptmp = NULL;
return NULL;
}
-int a2i_ipadd(unsigned char *ipout, const char *ipasc)
+int ossl_a2i_ipadd(unsigned char *ipout, const char *ipasc)
{
/* If string contains a ':' assume IPv6 */
static int ipv4_from_asc(unsigned char *v4, const char *in)
{
- int a0, a1, a2, a3;
- if (sscanf(in, "%d.%d.%d.%d", &a0, &a1, &a2, &a3) != 4)
+ const char *p;
+ int a0, a1, a2, a3, n;
+
+ if (sscanf(in, "%d.%d.%d.%d%n", &a0, &a1, &a2, &a3, &n) != 4)
return 0;
if ((a0 < 0) || (a0 > 255) || (a1 < 0) || (a1 > 255)
|| (a2 < 0) || (a2 > 255) || (a3 < 0) || (a3 > 255))
return 0;
+ p = in + n;
+ if (!(*p == '\0' || ossl_isspace(*p)))
+ return 0;
v4[0] = a0;
v4[1] = a1;
v4[2] = a2;
static int ipv6_from_asc(unsigned char *v6, const char *in)
{
IPV6_STAT v6stat;
+
v6stat.total = 0;
v6stat.zero_pos = -1;
v6stat.zero_cnt = 0;
if (v6stat.total == 16)
return 0;
/* More than three zeroes is an error */
- if (v6stat.zero_cnt > 3)
+ if (v6stat.zero_cnt > 3) {
return 0;
/* Can only have three zeroes if nothing else present */
- else if (v6stat.zero_cnt == 3) {
+ } else if (v6stat.zero_cnt == 3) {
if (v6stat.total > 0)
return 0;
- }
- /* Can only have two zeroes if at start or end */
- else if (v6stat.zero_cnt == 2) {
+ } else if (v6stat.zero_cnt == 2) {
+ /* Can only have two zeroes if at start or end */
if ((v6stat.zero_pos != 0)
&& (v6stat.zero_pos != v6stat.total))
return 0;
- } else
+ } else {
/* Can only have one zero if *not* start or end */
- {
if ((v6stat.zero_pos == 0)
|| (v6stat.zero_pos == v6stat.total))
return 0;
memcpy(v6 + v6stat.zero_pos + 16 - v6stat.total,
v6stat.tmp + v6stat.zero_pos,
v6stat.total - v6stat.zero_pos);
- } else
+ } else {
memcpy(v6, v6stat.tmp, 16);
+ }
return 1;
}
static int ipv6_cb(const char *elem, int len, void *usr)
{
IPV6_STAT *s = usr;
+
/* Error if 16 bytes written */
if (s->total == 16)
return 0;
CONF_VALUE *v;
int i, mval, spec_char, plus_char;
char *p, *type;
+
if (!nm)
return 0;
spec_char = ((*p == ':') || (*p == ',') || (*p == '.'));
#else
spec_char = ((*p == os_toascii[':']) || (*p == os_toascii[','])
- || (*p == os_toascii['.']));
+ || (*p == os_toascii['.']));
#endif
if (spec_char) {
p++;
if (plus_char) {
mval = -1;
type++;
- } else
+ } else {
mval = 0;
+ }
if (!X509_NAME_add_entry_by_txt(nm, type, chtype,
(unsigned char *)v->value, -1, -1,
mval))