提交 4e5d3a7f 编写于 作者: D Dr. Stephen Henson

IPv6 display and input support for extensions usingh GeneralName.

上级 379e5689
......@@ -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
......
/* 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))
......
/* 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;
}
......@@ -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
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册