IPv6 display and input support for extensions usingh GeneralName.
This commit is contained in:
parent
379e568950
commit
4e5d3a7f98
6
CHANGES
6
CHANGES
@ -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
|
||||
|
@ -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))
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user