Commit 4e5d3a7f authored by Dr. Stephen Henson's avatar Dr. Stephen Henson
Browse files

IPv6 display and input support for extensions usingh GeneralName.

parent 379e5689
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -4,6 +4,12 @@

 Changes between 0.9.7 and 0.9.8  [xx XXX xxxx]

  *) IPv6 support for certificate extensions. The various extensions
     which use the IP:a.b.c.d can now take IPv6 addresses using the
     formats of RFC1884 2.2 . IPv6 addresses are now also displayed
     correctly.
     [Steve Henson]

  *) Added an ENGINE that implements RSA by performing private key
     exponentiations with the GMP library. The conversions to and from
     GMP's mpz_t format aren't optimised nor are any montgomery forms
+41 −23
Original line number Diff line number Diff line
/* 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))
+208 −2
Original line number Diff line number Diff line
/* 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;
	}
+1 −0
Original line number Diff line number Diff line
@@ -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