aboutsummaryrefslogtreecommitdiff
path: root/crypto/x509v3
diff options
context:
space:
mode:
authorDr. Stephen Henson <steve@openssl.org>2003-02-05 00:34:31 +0000
committerDr. Stephen Henson <steve@openssl.org>2003-02-05 00:34:31 +0000
commit4e5d3a7f986c8ade22793a848e95447fafafece0 (patch)
tree618eb398b23d93a27ba7cd4cf10f029b8b79f9c3 /crypto/x509v3
parent379e568950b365b07f67b9dccc2bbb9b46797e2c (diff)
downloadopenssl-4e5d3a7f986c8ade22793a848e95447fafafece0.zip
openssl-4e5d3a7f986c8ade22793a848e95447fafafece0.tar.gz
openssl-4e5d3a7f986c8ade22793a848e95447fafafece0.tar.bz2
IPv6 display and input support for extensions usingh GeneralName.
Diffstat (limited to 'crypto/x509v3')
-rw-r--r--crypto/x509v3/v3_alt.c64
-rw-r--r--crypto/x509v3/v3_utl.c210
-rw-r--r--crypto/x509v3/x509v3.h1
3 files changed, 250 insertions, 25 deletions
diff --git a/crypto/x509v3/v3_alt.c b/crypto/x509v3/v3_alt.c
index baa9ca1..64e51d6 100644
--- a/crypto/x509v3/v3_alt.c
+++ b/crypto/x509v3/v3_alt.c
@@ -1,9 +1,9 @@
/* v3_alt.c */
/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL
- * project 1999.
+ * project.
*/
/* ====================================================================
- * Copyright (c) 1999-2002 The OpenSSL Project. All rights reserved.
+ * Copyright (c) 1999-2003 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -100,7 +100,8 @@ STACK_OF(CONF_VALUE) *i2v_GENERAL_NAME(X509V3_EXT_METHOD *method,
GENERAL_NAME *gen, STACK_OF(CONF_VALUE) *ret)
{
unsigned char *p;
- char oline[256];
+ char oline[256], htmp[5];
+ int i;
switch (gen->type)
{
case GEN_OTHERNAME:
@@ -134,12 +135,25 @@ STACK_OF(CONF_VALUE) *i2v_GENERAL_NAME(X509V3_EXT_METHOD *method,
case GEN_IPADD:
p = gen->d.ip->data;
- /* BUG: doesn't support IPV6 */
- if(gen->d.ip->length != 4) {
+ if(gen->d.ip->length == 4)
+ sprintf(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++)
+ {
+ sprintf(htmp, "%X", p[0] << 8 | p[1]);
+ p += 2;
+ strcat(oline, htmp);
+ if (i != 7)
+ strcat(oline, ":");
+ }
+ }
+ else
+ {
X509V3_add_value("IP Address","<invalid>", &ret);
break;
- }
- sprintf(oline, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
+ }
X509V3_add_value("IP Address",oline, &ret);
break;
@@ -154,6 +168,7 @@ STACK_OF(CONF_VALUE) *i2v_GENERAL_NAME(X509V3_EXT_METHOD *method,
int GENERAL_NAME_print(BIO *out, GENERAL_NAME *gen)
{
unsigned char *p;
+ int i;
switch (gen->type)
{
case GEN_OTHERNAME:
@@ -188,12 +203,24 @@ int GENERAL_NAME_print(BIO *out, GENERAL_NAME *gen)
case GEN_IPADD:
p = gen->d.ip->data;
- /* BUG: doesn't support IPV6 */
- if(gen->d.ip->length != 4) {
+ 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;
+ }
+ BIO_puts(out, "\n");
+ }
+ else
+ {
BIO_printf(out,"IP Address:<invalid>");
break;
- }
- BIO_printf(out, "IP Address:%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
+ }
break;
case GEN_RID:
@@ -418,21 +445,12 @@ if(!name_cmp(name, "email")) {
gen->d.rid = obj;
type = GEN_RID;
} else if(!name_cmp(name, "IP")) {
- int i1,i2,i3,i4;
- unsigned char ip[4];
- if((sscanf(value, "%d.%d.%d.%d",&i1,&i2,&i3,&i4) != 4) ||
- (i1 < 0) || (i1 > 255) || (i2 < 0) || (i2 > 255) ||
- (i3 < 0) || (i3 > 255) || (i4 < 0) || (i4 > 255) ) {
+ if(!(gen->d.ip = a2i_IPADDRESS(value)))
+ {
X509V3err(X509V3_F_V2I_GENERAL_NAME,X509V3_R_BAD_IP_ADDRESS);
ERR_add_error_data(2, "value=", value);
goto err;
- }
- ip[0] = i1; ip[1] = i2 ; ip[2] = i3 ; ip[3] = i4;
- if(!(gen->d.ip = M_ASN1_OCTET_STRING_new()) ||
- !ASN1_STRING_set(gen->d.ip, ip, 4)) {
- X509V3err(X509V3_F_V2I_GENERAL_NAME,ERR_R_MALLOC_FAILURE);
- goto err;
- }
+ }
type = GEN_IPADD;
} else if(!name_cmp(name, "otherName")) {
if (!do_othername(gen, value, ctx))
diff --git a/crypto/x509v3/v3_utl.c b/crypto/x509v3/v3_utl.c
index a11243d..4b85378 100644
--- a/crypto/x509v3/v3_utl.c
+++ b/crypto/x509v3/v3_utl.c
@@ -1,9 +1,9 @@
/* v3_utl.c */
/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL
- * project 1999.
+ * project.
*/
/* ====================================================================
- * Copyright (c) 1999 The OpenSSL Project. All rights reserved.
+ * Copyright (c) 1999-2003 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -70,6 +70,11 @@ static STACK *get_email(X509_NAME *name, GENERAL_NAMES *gens);
static void str_free(void *str);
static int append_ia5(STACK **sk, 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);
+static int ipv6_cb(const char *elem, int len, void *usr);
+static int ipv6_hex(unsigned char *out, const char *in, int inlen);
+
/* Add a CONF_VALUE name value pair to stack */
int X509V3_add_value(const char *name, const char *value,
@@ -534,3 +539,204 @@ void X509_email_free(STACK *sk)
{
sk_pop_free(sk, str_free);
}
+
+/* Convert IP addresses both IPv4 and IPv6 into an
+ * OCTET STRING compatible with RFC3280.
+ */
+
+ASN1_OCTET_STRING *a2i_IPADDRESS(const char *ipasc)
+ {
+ unsigned char ipout[16];
+ ASN1_OCTET_STRING *ret;
+ int iplen;
+
+ /* If string contains a ':' assume IPv6 */
+
+ if (strchr(ipasc, ':'))
+ {
+ if (!ipv6_from_asc(ipout, ipasc))
+ return NULL;
+ iplen = 16;
+ }
+ else
+ {
+ if (!ipv4_from_asc(ipout, ipasc))
+ return NULL;
+ iplen = 4;
+ }
+
+ ret = ASN1_OCTET_STRING_new();
+ if (!ret)
+ return NULL;
+ if (!ASN1_OCTET_STRING_set(ret, ipout, iplen))
+ {
+ ASN1_OCTET_STRING_free(ret);
+ return NULL;
+ }
+ return ret;
+ }
+
+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)
+ return 0;
+ if ((a0 < 0) || (a0 > 255) || (a1 < 0) || (a1 > 255)
+ || (a2 < 0) || (a2 > 255) || (a3 < 0) || (a3 > 255))
+ return 0;
+ v4[0] = a0;
+ v4[1] = a1;
+ v4[2] = a2;
+ v4[3] = a3;
+ return 1;
+ }
+
+typedef struct {
+ /* Temporary store for IPV6 output */
+ unsigned char tmp[16];
+ /* Total number of bytes in tmp */
+ int total;
+ /* The position of a zero (corresponding to '::') */
+ int zero_pos;
+ /* Number of zeroes */
+ int zero_cnt;
+ } IPV6_STAT;
+
+
+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;
+ /* Treat the IPv6 representation as a list of values
+ * separated by ':'. The presence of a '::' will parse
+ * as one, two or three zero length elements.
+ */
+ if (!CONF_parse_list(in, ':', 0, ipv6_cb, &v6stat))
+ return 0;
+
+ /* Now for some sanity checks */
+
+ if (v6stat.zero_pos == -1)
+ {
+ /* If no '::' must have exactly 16 bytes */
+ if (v6stat.total != 16)
+ return 0;
+ }
+ else
+ {
+ /* If '::' must have less than 16 bytes */
+ if (v6stat.total == 16)
+ return 0;
+ /* More than three zeroes is an error */
+ if (v6stat.zero_cnt > 3)
+ return 0;
+ /* Can only have three zeroes if nothing else present */
+ 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)
+ {
+ if ((v6stat.zero_pos != 0)
+ && (v6stat.zero_pos != v6stat.total))
+ return 0;
+ }
+ else
+ /* Can only have one zero if *not* start or end */
+ {
+ if ((v6stat.zero_pos == 0)
+ || (v6stat.zero_pos == v6stat.total))
+ return 0;
+ }
+ }
+
+ /* Format result */
+
+ /* Copy initial part */
+ if (v6stat.zero_pos > 0)
+ memcpy(v6, v6stat.tmp, v6stat.zero_pos);
+ /* Zero middle */
+ if (v6stat.total != 16)
+ memset(v6 + v6stat.zero_pos, 0, 16 - v6stat.total);
+ /* Copy final part */
+ if (v6stat.total != v6stat.zero_pos)
+ memcpy(v6 + v6stat.zero_pos + 16 - v6stat.total,
+ v6stat.tmp + v6stat.zero_pos,
+ v6stat.total - v6stat.zero_pos);
+
+ 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;
+ if (len == 0)
+ {
+ /* Zero length element, corresponds to '::' */
+ if (s->zero_pos == -1)
+ s->zero_pos = s->total;
+ /* If we've already got a :: its an error */
+ else if (s->zero_pos != s->total)
+ return 0;
+ s->zero_cnt++;
+ }
+ else
+ {
+ /* If more than 4 characters could be final a.b.c.d form */
+ if (len > 4)
+ {
+ /* Need at least 4 bytes left */
+ if (s->total > 12)
+ return 0;
+ /* Must be end of string */
+ if (elem[len])
+ return 0;
+ if (!ipv4_from_asc(s->tmp + s->total, elem))
+ return 0;
+ s->total += 4;
+ }
+ else
+ {
+ if (!ipv6_hex(s->tmp + s->total, elem, len))
+ return 0;
+ s->total += 2;
+ }
+ }
+ return 1;
+ }
+
+/* Convert a string of up to 4 hex digits into the corresponding
+ * IPv6 form.
+ */
+
+static int ipv6_hex(unsigned char *out, const char *in, int inlen)
+ {
+ unsigned char c;
+ unsigned int num = 0;
+ if (inlen > 4)
+ return 0;
+ while(inlen--)
+ {
+ c = *in++;
+ num <<= 4;
+ if ((c >= '0') && (c <= '9'))
+ num |= c - '0';
+ else if ((c >= 'A') && (c <= 'F'))
+ num |= c - 'A' + 10;
+ else if ((c >= 'a') && (c <= 'f'))
+ num |= c - 'a' + 10;
+ else
+ return 0;
+ }
+ out[0] = num >> 8;
+ out[1] = num & 0xff;
+ return 1;
+ }
+
diff --git a/crypto/x509v3/x509v3.h b/crypto/x509v3/x509v3.h
index b4dd52a..a720ff2 100644
--- a/crypto/x509v3/x509v3.h
+++ b/crypto/x509v3/x509v3.h
@@ -547,6 +547,7 @@ STACK *X509_get1_email(X509 *x);
STACK *X509_REQ_get1_email(X509_REQ *x);
void X509_email_free(STACK *sk);
+ASN1_OCTET_STRING *a2i_IPADDRESS(const char *ipasc);
/* BEGIN ERROR CODES */
/* The following lines are auto generated by the script mkerr.pl. Any changes