aboutsummaryrefslogtreecommitdiff
path: root/openssl
diff options
context:
space:
mode:
authorRob Austein <sra@hactrn.net>2006-10-09 17:01:30 +0000
committerRob Austein <sra@hactrn.net>2006-10-09 17:01:30 +0000
commit77dbc9affdf4c03dd09778b961c24177145a8371 (patch)
tree76593072ba2453e870fe3df303d0e1892b440a78 /openssl
parent4043d7db4e466d15193c3bad3b204048fc13b785 (diff)
Add cleaned-up patch I've been using on FreeBSD machines.
svn path=/openssl/patch-rpki-openssl-0.9.8; revision=378
Diffstat (limited to 'openssl')
-rw-r--r--openssl/patch-rpki-openssl-0.9.82656
1 files changed, 2656 insertions, 0 deletions
diff --git a/openssl/patch-rpki-openssl-0.9.8 b/openssl/patch-rpki-openssl-0.9.8
new file mode 100644
index 00000000..eed46ba6
--- /dev/null
+++ b/openssl/patch-rpki-openssl-0.9.8
@@ -0,0 +1,2656 @@
+$URL$
+$Id$
+
+This is a patch against the OpenSSL 0.9.8 branch. It was originally
+developed for 0.9.8b, but applies unchanged against 0.9.8c and 0.9.8d.
+If you run FreeBSD, you can just drop this patch into
+/usr/ports/security/openssl/files-beta/ and build build the port to
+add RPKI functionality to OpenSSL.
+
+Index: crypto/stack/safestack.h
+===================================================================
+--- crypto/stack/safestack.h (.../vendor/0.9.8b) (revision 251)
++++ crypto/stack/safestack.h (.../trunk) (revision 251)
+@@ -234,6 +234,28 @@
+ #define sk_ACCESS_DESCRIPTION_sort(st) SKM_sk_sort(ACCESS_DESCRIPTION, (st))
+ #define sk_ACCESS_DESCRIPTION_is_sorted(st) SKM_sk_is_sorted(ACCESS_DESCRIPTION, (st))
+
++#define sk_ASIdOrRange_new(st) SKM_sk_new(ASIdOrRange, (st))
++#define sk_ASIdOrRange_new_null() SKM_sk_new_null(ASIdOrRange)
++#define sk_ASIdOrRange_free(st) SKM_sk_free(ASIdOrRange, (st))
++#define sk_ASIdOrRange_num(st) SKM_sk_num(ASIdOrRange, (st))
++#define sk_ASIdOrRange_value(st, i) SKM_sk_value(ASIdOrRange, (st), (i))
++#define sk_ASIdOrRange_set(st, i, val) SKM_sk_set(ASIdOrRange, (st), (i), (val))
++#define sk_ASIdOrRange_zero(st) SKM_sk_zero(ASIdOrRange, (st))
++#define sk_ASIdOrRange_push(st, val) SKM_sk_push(ASIdOrRange, (st), (val))
++#define sk_ASIdOrRange_unshift(st, val) SKM_sk_unshift(ASIdOrRange, (st), (val))
++#define sk_ASIdOrRange_find(st, val) SKM_sk_find(ASIdOrRange, (st), (val))
++#define sk_ASIdOrRange_find_ex(st, val) SKM_sk_find_ex(ASIdOrRange, (st), (val))
++#define sk_ASIdOrRange_delete(st, i) SKM_sk_delete(ASIdOrRange, (st), (i))
++#define sk_ASIdOrRange_delete_ptr(st, ptr) SKM_sk_delete_ptr(ASIdOrRange, (st), (ptr))
++#define sk_ASIdOrRange_insert(st, val, i) SKM_sk_insert(ASIdOrRange, (st), (val), (i))
++#define sk_ASIdOrRange_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(ASIdOrRange, (st), (cmp))
++#define sk_ASIdOrRange_dup(st) SKM_sk_dup(ASIdOrRange, st)
++#define sk_ASIdOrRange_pop_free(st, free_func) SKM_sk_pop_free(ASIdOrRange, (st), (free_func))
++#define sk_ASIdOrRange_shift(st) SKM_sk_shift(ASIdOrRange, (st))
++#define sk_ASIdOrRange_pop(st) SKM_sk_pop(ASIdOrRange, (st))
++#define sk_ASIdOrRange_sort(st) SKM_sk_sort(ASIdOrRange, (st))
++#define sk_ASIdOrRange_is_sorted(st) SKM_sk_is_sorted(ASIdOrRange, (st))
++
+ #define sk_ASN1_GENERALSTRING_new(st) SKM_sk_new(ASN1_GENERALSTRING, (st))
+ #define sk_ASN1_GENERALSTRING_new_null() SKM_sk_new_null(ASN1_GENERALSTRING)
+ #define sk_ASN1_GENERALSTRING_free(st) SKM_sk_free(ASN1_GENERALSTRING, (st))
+@@ -608,6 +630,50 @@
+ #define sk_GENERAL_SUBTREE_sort(st) SKM_sk_sort(GENERAL_SUBTREE, (st))
+ #define sk_GENERAL_SUBTREE_is_sorted(st) SKM_sk_is_sorted(GENERAL_SUBTREE, (st))
+
++#define sk_IPAddressFamily_new(st) SKM_sk_new(IPAddressFamily, (st))
++#define sk_IPAddressFamily_new_null() SKM_sk_new_null(IPAddressFamily)
++#define sk_IPAddressFamily_free(st) SKM_sk_free(IPAddressFamily, (st))
++#define sk_IPAddressFamily_num(st) SKM_sk_num(IPAddressFamily, (st))
++#define sk_IPAddressFamily_value(st, i) SKM_sk_value(IPAddressFamily, (st), (i))
++#define sk_IPAddressFamily_set(st, i, val) SKM_sk_set(IPAddressFamily, (st), (i), (val))
++#define sk_IPAddressFamily_zero(st) SKM_sk_zero(IPAddressFamily, (st))
++#define sk_IPAddressFamily_push(st, val) SKM_sk_push(IPAddressFamily, (st), (val))
++#define sk_IPAddressFamily_unshift(st, val) SKM_sk_unshift(IPAddressFamily, (st), (val))
++#define sk_IPAddressFamily_find(st, val) SKM_sk_find(IPAddressFamily, (st), (val))
++#define sk_IPAddressFamily_find_ex(st, val) SKM_sk_find_ex(IPAddressFamily, (st), (val))
++#define sk_IPAddressFamily_delete(st, i) SKM_sk_delete(IPAddressFamily, (st), (i))
++#define sk_IPAddressFamily_delete_ptr(st, ptr) SKM_sk_delete_ptr(IPAddressFamily, (st), (ptr))
++#define sk_IPAddressFamily_insert(st, val, i) SKM_sk_insert(IPAddressFamily, (st), (val), (i))
++#define sk_IPAddressFamily_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(IPAddressFamily, (st), (cmp))
++#define sk_IPAddressFamily_dup(st) SKM_sk_dup(IPAddressFamily, st)
++#define sk_IPAddressFamily_pop_free(st, free_func) SKM_sk_pop_free(IPAddressFamily, (st), (free_func))
++#define sk_IPAddressFamily_shift(st) SKM_sk_shift(IPAddressFamily, (st))
++#define sk_IPAddressFamily_pop(st) SKM_sk_pop(IPAddressFamily, (st))
++#define sk_IPAddressFamily_sort(st) SKM_sk_sort(IPAddressFamily, (st))
++#define sk_IPAddressFamily_is_sorted(st) SKM_sk_is_sorted(IPAddressFamily, (st))
++
++#define sk_IPAddressOrRange_new(st) SKM_sk_new(IPAddressOrRange, (st))
++#define sk_IPAddressOrRange_new_null() SKM_sk_new_null(IPAddressOrRange)
++#define sk_IPAddressOrRange_free(st) SKM_sk_free(IPAddressOrRange, (st))
++#define sk_IPAddressOrRange_num(st) SKM_sk_num(IPAddressOrRange, (st))
++#define sk_IPAddressOrRange_value(st, i) SKM_sk_value(IPAddressOrRange, (st), (i))
++#define sk_IPAddressOrRange_set(st, i, val) SKM_sk_set(IPAddressOrRange, (st), (i), (val))
++#define sk_IPAddressOrRange_zero(st) SKM_sk_zero(IPAddressOrRange, (st))
++#define sk_IPAddressOrRange_push(st, val) SKM_sk_push(IPAddressOrRange, (st), (val))
++#define sk_IPAddressOrRange_unshift(st, val) SKM_sk_unshift(IPAddressOrRange, (st), (val))
++#define sk_IPAddressOrRange_find(st, val) SKM_sk_find(IPAddressOrRange, (st), (val))
++#define sk_IPAddressOrRange_find_ex(st, val) SKM_sk_find_ex(IPAddressOrRange, (st), (val))
++#define sk_IPAddressOrRange_delete(st, i) SKM_sk_delete(IPAddressOrRange, (st), (i))
++#define sk_IPAddressOrRange_delete_ptr(st, ptr) SKM_sk_delete_ptr(IPAddressOrRange, (st), (ptr))
++#define sk_IPAddressOrRange_insert(st, val, i) SKM_sk_insert(IPAddressOrRange, (st), (val), (i))
++#define sk_IPAddressOrRange_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(IPAddressOrRange, (st), (cmp))
++#define sk_IPAddressOrRange_dup(st) SKM_sk_dup(IPAddressOrRange, st)
++#define sk_IPAddressOrRange_pop_free(st, free_func) SKM_sk_pop_free(IPAddressOrRange, (st), (free_func))
++#define sk_IPAddressOrRange_shift(st) SKM_sk_shift(IPAddressOrRange, (st))
++#define sk_IPAddressOrRange_pop(st) SKM_sk_pop(IPAddressOrRange, (st))
++#define sk_IPAddressOrRange_sort(st) SKM_sk_sort(IPAddressOrRange, (st))
++#define sk_IPAddressOrRange_is_sorted(st) SKM_sk_is_sorted(IPAddressOrRange, (st))
++
+ #define sk_KRB5_APREQBODY_new(st) SKM_sk_new(KRB5_APREQBODY, (st))
+ #define sk_KRB5_APREQBODY_new_null() SKM_sk_new_null(KRB5_APREQBODY)
+ #define sk_KRB5_APREQBODY_free(st) SKM_sk_free(KRB5_APREQBODY, (st))
+
+Index: crypto/x509v3/v3_purp.c
+===================================================================
+--- crypto/x509v3/v3_purp.c (.../vendor/0.9.8b) (revision 251)
++++ crypto/x509v3/v3_purp.c (.../trunk) (revision 251)
+@@ -285,7 +285,10 @@
+ NID_key_usage, /* 83 */
+ NID_subject_alt_name, /* 85 */
+ NID_basic_constraints, /* 87 */
++ NID_certificate_policies, /* 89 */
+ NID_ext_key_usage, /* 126 */
++ NID_sbgp_ipAddrBlock, /* 290 */
++ NID_sbgp_autonomousSysNum, /* 291 */
+ NID_proxyCertInfo /* 661 */
+ };
+
+@@ -410,6 +413,9 @@
+ }
+ x->skid =X509_get_ext_d2i(x, NID_subject_key_identifier, NULL, NULL);
+ x->akid =X509_get_ext_d2i(x, NID_authority_key_identifier, NULL, NULL);
++ x->rfc3779_addr =X509_get_ext_d2i(x, NID_sbgp_ipAddrBlock, NULL, NULL);
++ x->rfc3779_asid =X509_get_ext_d2i(x, NID_sbgp_autonomousSysNum,
++ NULL, NULL);
+ for (i = 0; i < X509_get_ext_count(x); i++)
+ {
+ ex = X509_get_ext(x, i);
+Index: crypto/x509v3/v3_utl.c
+===================================================================
+--- crypto/x509v3/v3_utl.c (.../vendor/0.9.8b) (revision 251)
++++ crypto/x509v3/v3_utl.c (.../trunk) (revision 251)
+@@ -71,7 +71,6 @@
+ static void str_free(void *str);
+ static int append_ia5(STACK **sk, ASN1_IA5STRING *email);
+
+-static int a2i_ipadd(unsigned char *ipout, const char *ipasc);
+ 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);
+@@ -615,7 +614,7 @@
+ }
+
+
+-static int a2i_ipadd(unsigned char *ipout, const char *ipasc)
++int a2i_ipadd(unsigned char *ipout, const char *ipasc)
+ {
+ /* If string contains a ':' assume IPv6 */
+
+Index: crypto/x509v3/x509v3.h
+===================================================================
+--- crypto/x509v3/x509v3.h (.../vendor/0.9.8b) (revision 251)
++++ crypto/x509v3/x509v3.h (.../trunk) (revision 251)
+@@ -620,11 +620,143 @@
+
+ ASN1_OCTET_STRING *a2i_IPADDRESS(const char *ipasc);
+ ASN1_OCTET_STRING *a2i_IPADDRESS_NC(const char *ipasc);
++int a2i_ipadd(unsigned char *ipout, const char *ipasc);
+ int X509V3_NAME_from_section(X509_NAME *nm, STACK_OF(CONF_VALUE)*dn_sk,
+ unsigned long chtype);
+
+ void X509_POLICY_NODE_print(BIO *out, X509_POLICY_NODE *node, int indent);
+
++/*
++ * [sra] Begin RFC 3779 stuff
++ *
++ * The following definitions and declarations will need to be merged
++ * into the the rest of this file more cleanly. Right now they're
++ * organized as a unit to make it easier to see what I've added.
++ */
++
++typedef struct ASRange_st {
++ ASN1_INTEGER *min, *max;
++} ASRange;
++
++#define ASIdOrRange_id 0
++#define ASIdOrRange_range 1
++
++typedef struct ASIdOrRange_st {
++ int type;
++ union {
++ ASN1_INTEGER *id;
++ ASRange *range;
++ } u;
++} ASIdOrRange;
++
++typedef STACK_OF(ASIdOrRange) ASIdOrRanges;
++DECLARE_STACK_OF(ASIdOrRange)
++
++#define ASIdentifierChoice_inherit 0
++#define ASIdentifierChoice_asIdsOrRanges 1
++
++typedef struct ASIdentifierChoice_st {
++ int type;
++ union {
++ ASN1_NULL *inherit;
++ ASIdOrRanges *asIdsOrRanges;
++ } u;
++} ASIdentifierChoice;
++
++typedef struct ASIdentifiers_st {
++ ASIdentifierChoice *asnum, *rdi;
++} ASIdentifiers;
++
++DECLARE_ASN1_FUNCTIONS(ASRange)
++DECLARE_ASN1_FUNCTIONS(ASIdOrRange)
++DECLARE_ASN1_FUNCTIONS(ASIdentifierChoice)
++DECLARE_ASN1_FUNCTIONS(ASIdentifiers)
++
++
++typedef struct IPAddressRange_st {
++ ASN1_BIT_STRING *min, *max;
++} IPAddressRange;
++
++#define IPAddressOrRange_addressPrefix 0
++#define IPAddressOrRange_addressRange 1
++
++typedef struct IPAddressOrRange_st {
++ int type;
++ union {
++ ASN1_BIT_STRING *addressPrefix;
++ IPAddressRange *addressRange;
++ } u;
++} IPAddressOrRange;
++
++typedef STACK_OF(IPAddressOrRange) IPAddressOrRanges;
++DECLARE_STACK_OF(IPAddressOrRange)
++
++#define IPAddressChoice_inherit 0
++#define IPAddressChoice_addressesOrRanges 1
++
++typedef struct IPAddressChoice_st {
++ int type;
++ union {
++ ASN1_NULL *inherit;
++ IPAddressOrRanges *addressesOrRanges;
++ } u;
++} IPAddressChoice;
++
++typedef struct IPAddressFamily_st {
++ ASN1_OCTET_STRING *addressFamily;
++ IPAddressChoice *ipAddressChoice;
++} IPAddressFamily;
++
++typedef STACK_OF(IPAddressFamily) IPAddrBlocks;
++DECLARE_STACK_OF(IPAddressFamily)
++
++DECLARE_ASN1_FUNCTIONS(IPAddressRange)
++DECLARE_ASN1_FUNCTIONS(IPAddressOrRange)
++DECLARE_ASN1_FUNCTIONS(IPAddressChoice)
++DECLARE_ASN1_FUNCTIONS(IPAddressFamily)
++
++/*
++ * AFI values, assigned by IANA. It'd be nice to make the AFI
++ * handling code totally generic, but there are too many little things
++ * that would need to be defined for other address families for it to
++ * be worth the trouble.
++ */
++
++#define IANA_AFI_IPV4 1
++#define IANA_AFI_IPV6 2
++
++/*
++ * Canonical forms.
++ */
++int v3_asid_is_canonical(ASIdentifiers *asid);
++int v3_addr_is_canonical(IPAddrBlocks *addr);
++int v3_asid_canonize(ASIdentifiers *asid);
++int v3_addr_canonize(IPAddrBlocks *addr);
++
++/*
++ * Tests for inheritance and containment.
++ */
++int v3_asid_inherits(ASIdentifiers *asid);
++int v3_addr_inherits(IPAddrBlocks *addr);
++int v3_asid_subset(ASIdentifiers *a, ASIdentifiers *b);
++int v3_addr_subset(IPAddrBlocks *a, IPAddrBlocks *b);
++
++/*
++ * Check whether RFC 3779 extensions nest properly in chains.
++ */
++int v3_asid_validate_path(X509_STORE_CTX *);
++int v3_addr_validate_path(X509_STORE_CTX *);
++int v3_asid_validate_resource_set(STACK_OF(X509) *chain,
++ ASIdentifiers *ext,
++ int allow_inheritance);
++int v3_addr_validate_resource_set(STACK_OF(X509) *chain,
++ IPAddrBlocks *ext,
++ int allow_inheritance);
++
++/*
++ * [sra] End RFC 3779 stuff
++ */
++
+ /* BEGIN ERROR CODES */
+ /* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+@@ -634,6 +766,8 @@
+ /* Error codes for the X509V3 functions. */
+
+ /* Function codes. */
++#define X509V3_F_ASIDENTIFIERCHOICE_CANONIZE 156
++#define X509V3_F_ASIDENTIFIERCHOICE_IS_CANONICAL 157
+ #define X509V3_F_COPY_EMAIL 122
+ #define X509V3_F_COPY_ISSUER 123
+ #define X509V3_F_DO_DIRNAME 144
+@@ -663,6 +797,7 @@
+ #define X509V3_F_SXNET_ADD_ID_ULONG 127
+ #define X509V3_F_SXNET_GET_ID_ASC 128
+ #define X509V3_F_SXNET_GET_ID_ULONG 129
++#define X509V3_F_V2I_ASIDENTIFIERS 158
+ #define X509V3_F_V2I_ASN1_BIT_STRING 101
+ #define X509V3_F_V2I_AUTHORITY_INFO_ACCESS 139
+ #define X509V3_F_V2I_AUTHORITY_KEYID 119
+@@ -671,11 +806,13 @@
+ #define X509V3_F_V2I_EXTENDED_KEY_USAGE 103
+ #define X509V3_F_V2I_GENERAL_NAMES 118
+ #define X509V3_F_V2I_GENERAL_NAME_EX 117
++#define X509V3_F_V2I_IPADDRBLOCKS 159
+ #define X509V3_F_V2I_ISSUER_ALT 153
+ #define X509V3_F_V2I_NAME_CONSTRAINTS 147
+ #define X509V3_F_V2I_POLICY_CONSTRAINTS 146
+ #define X509V3_F_V2I_POLICY_MAPPINGS 145
+ #define X509V3_F_V2I_SUBJECT_ALT 154
++#define X509V3_F_V3_ADDR_VALIDATE_PATH_INTERNAL 160
+ #define X509V3_F_V3_GENERIC_EXTENSION 116
+ #define X509V3_F_X509V3_ADD1_I2D 140
+ #define X509V3_F_X509V3_ADD_VALUE 105
+@@ -710,8 +847,12 @@
+ #define X509V3_R_ILLEGAL_EMPTY_EXTENSION 151
+ #define X509V3_R_ILLEGAL_HEX_DIGIT 113
+ #define X509V3_R_INCORRECT_POLICY_SYNTAX_TAG 152
++#define X509V3_R_INVALID_ASNUMBER 160
++#define X509V3_R_INVALID_ASRANGE 161
+ #define X509V3_R_INVALID_BOOLEAN_STRING 104
+ #define X509V3_R_INVALID_EXTENSION_STRING 105
++#define X509V3_R_INVALID_INHERITANCE 162
++#define X509V3_R_INVALID_IPADDRESS 163
+ #define X509V3_R_INVALID_NAME 106
+ #define X509V3_R_INVALID_NULL_ARGUMENT 107
+ #define X509V3_R_INVALID_NULL_NAME 108
+@@ -723,6 +864,7 @@
+ #define X509V3_R_INVALID_POLICY_IDENTIFIER 134
+ #define X509V3_R_INVALID_PROXY_POLICY_SETTING 153
+ #define X509V3_R_INVALID_PURPOSE 146
++#define X509V3_R_INVALID_SAFI 164
+ #define X509V3_R_INVALID_SECTION 135
+ #define X509V3_R_INVALID_SYNTAX 143
+ #define X509V3_R_ISSUER_DECODE_ERROR 126
+Index: crypto/x509v3/v3_asid.c
+===================================================================
+--- crypto/x509v3/v3_asid.c (.../vendor/0.9.8b) (revision 0)
++++ crypto/x509v3/v3_asid.c (.../trunk) (revision 251)
+@@ -0,0 +1,778 @@
++/*
++ * Copyright (C) 2006 American Registry for Internet Numbers ("ARIN")
++ *
++ * Permission to use, copy, modify, and distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ARIN DISCLAIMS ALL WARRANTIES WITH
++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS. IN NO EVENT SHALL ARIN BE LIABLE FOR ANY SPECIAL, DIRECT,
++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/* $Id$ */
++
++/*
++ * Implementation of RFC 3779 section 3.2.
++ */
++
++#include <stdio.h>
++#include <string.h>
++#include <assert.h>
++#include "cryptlib.h"
++#include <openssl/conf.h>
++#include <openssl/asn1.h>
++#include <openssl/asn1t.h>
++#include <openssl/x509v3.h>
++#include <openssl/x509.h>
++#include <openssl/bn.h>
++
++/*
++ * OpenSSL ASN.1 template translation of RFC 3779 3.2.3.
++ */
++
++ASN1_SEQUENCE(ASRange) = {
++ ASN1_SIMPLE(ASRange, min, ASN1_INTEGER),
++ ASN1_SIMPLE(ASRange, max, ASN1_INTEGER)
++} ASN1_SEQUENCE_END(ASRange)
++
++ASN1_CHOICE(ASIdOrRange) = {
++ ASN1_SIMPLE(ASIdOrRange, u.id, ASN1_INTEGER),
++ ASN1_SIMPLE(ASIdOrRange, u.range, ASRange)
++} ASN1_CHOICE_END(ASIdOrRange)
++
++ASN1_CHOICE(ASIdentifierChoice) = {
++ ASN1_SIMPLE(ASIdentifierChoice, u.inherit, ASN1_NULL),
++ ASN1_SEQUENCE_OF(ASIdentifierChoice, u.asIdsOrRanges, ASIdOrRange)
++} ASN1_CHOICE_END(ASIdentifierChoice)
++
++ASN1_SEQUENCE(ASIdentifiers) = {
++ ASN1_EXP_OPT(ASIdentifiers, asnum, ASIdentifierChoice, 0),
++ ASN1_EXP_OPT(ASIdentifiers, rdi, ASIdentifierChoice, 1)
++} ASN1_SEQUENCE_END(ASIdentifiers)
++
++IMPLEMENT_ASN1_FUNCTIONS(ASRange)
++IMPLEMENT_ASN1_FUNCTIONS(ASIdOrRange)
++IMPLEMENT_ASN1_FUNCTIONS(ASIdentifierChoice)
++IMPLEMENT_ASN1_FUNCTIONS(ASIdentifiers)
++
++/*
++ * i2r method for an ASIdentifierChoice.
++ */
++static int i2r_ASIdentifierChoice(BIO *out,
++ ASIdentifierChoice *choice,
++ int indent,
++ const char *msg)
++{
++ int i;
++ char *s;
++ if (choice == NULL)
++ return 1;
++ BIO_printf(out, "%*s%s:\n", indent, "", msg);
++ switch (choice->type) {
++ case ASIdentifierChoice_inherit:
++ BIO_printf(out, "%*sinherit\n", indent + 2, "");
++ break;
++ case ASIdentifierChoice_asIdsOrRanges:
++ for (i = 0; i < sk_ASIdOrRange_num(choice->u.asIdsOrRanges); i++) {
++ ASIdOrRange *aor = sk_ASIdOrRange_value(choice->u.asIdsOrRanges, i);
++ switch (aor->type) {
++ case ASIdOrRange_id:
++ if ((s = i2s_ASN1_INTEGER(NULL, aor->u.id)) == NULL)
++ return 0;
++ BIO_printf(out, "%*s%s\n", indent + 2, "", s);
++ OPENSSL_free(s);
++ break;
++ case ASIdOrRange_range:
++ if ((s = i2s_ASN1_INTEGER(NULL, aor->u.range->min)) == NULL)
++ return 0;
++ BIO_printf(out, "%*s%s-", indent + 2, "", s);
++ OPENSSL_free(s);
++ if ((s = i2s_ASN1_INTEGER(NULL, aor->u.range->max)) == NULL)
++ return 0;
++ BIO_printf(out, "%s\n", s);
++ OPENSSL_free(s);
++ break;
++ default:
++ return 0;
++ }
++ }
++ break;
++ default:
++ return 0;
++ }
++ return 1;
++}
++
++/*
++ * i2r method for an ASIdentifier extension.
++ */
++static int i2r_ASIdentifiers(X509V3_EXT_METHOD *method,
++ void *ext,
++ BIO *out,
++ int indent)
++{
++ ASIdentifiers *asid = ext;
++ return (i2r_ASIdentifierChoice(out, asid->asnum, indent,
++ "Autonomous System Numbers") &&
++ i2r_ASIdentifierChoice(out, asid->rdi, indent,
++ "Routing Domain Identifiers"));
++}
++
++/*
++ * Comparision function for "stack" sorting.
++ */
++static int ASIdOrRange_cmp(const ASIdOrRange * const *a_,
++ const ASIdOrRange * const *b_)
++{
++ const ASIdOrRange *a = *a_, *b = *b_;
++
++ assert((a->type == ASIdOrRange_id && a->u.id != NULL) ||
++ (a->type == ASIdOrRange_range && a->u.range != NULL &&
++ a->u.range->min != NULL && a->u.range->max != NULL));
++
++ assert((b->type == ASIdOrRange_id && b->u.id != NULL) ||
++ (b->type == ASIdOrRange_range && b->u.range != NULL &&
++ b->u.range->min != NULL && b->u.range->max != NULL));
++
++ if (a->type == ASIdOrRange_id && b->type == ASIdOrRange_id)
++ return ASN1_INTEGER_cmp(a->u.id, b->u.id);
++
++ if (a->type == ASIdOrRange_range && b->type == ASIdOrRange_range) {
++ int r = ASN1_INTEGER_cmp(a->u.range->min, b->u.range->min);
++ return r != 0 ? r : ASN1_INTEGER_cmp(a->u.range->max, b->u.range->max);
++ }
++
++ if (a->type == ASIdOrRange_id)
++ return ASN1_INTEGER_cmp(a->u.id, b->u.range->min);
++ else
++ return ASN1_INTEGER_cmp(a->u.range->min, b->u.id);
++}
++
++/*
++ * Some of the following helper routines might want to become globals
++ * eventually.
++ */
++
++/*
++ * Add an inherit element to an ASIdentifierChoice.
++ */
++static int asid_add_inherit(ASIdentifierChoice **choice)
++{
++ if (*choice == NULL) {
++ if ((*choice = ASIdentifierChoice_new()) == NULL)
++ return 0;
++ assert((*choice)->u.inherit == NULL);
++ if (((*choice)->u.inherit = ASN1_NULL_new()) == NULL)
++ return 0;
++ (*choice)->type = ASIdentifierChoice_inherit;
++ }
++ return (*choice)->type == ASIdentifierChoice_inherit;
++}
++
++/*
++ * Add an ID or range to an ASIdentifierChoice.
++ */
++static int asid_add_id_or_range(ASIdentifierChoice **choice,
++ ASN1_INTEGER *min,
++ ASN1_INTEGER *max)
++{
++ ASIdOrRange *aor;
++ if (*choice != NULL && (*choice)->type == ASIdentifierChoice_inherit)
++ return 0;
++ if (*choice == NULL) {
++ if ((*choice = ASIdentifierChoice_new()) == NULL)
++ return 0;
++ assert((*choice)->u.asIdsOrRanges == NULL);
++ (*choice)->u.asIdsOrRanges = sk_ASIdOrRange_new(ASIdOrRange_cmp);
++ if ((*choice)->u.asIdsOrRanges == NULL)
++ return 0;
++ (*choice)->type = ASIdentifierChoice_asIdsOrRanges;
++ }
++ if ((aor = ASIdOrRange_new()) == NULL)
++ return 0;
++ if (max == NULL) {
++ aor->type = ASIdOrRange_id;
++ aor->u.id = min;
++ } else {
++ aor->type = ASIdOrRange_range;
++ if ((aor->u.range = ASRange_new()) == NULL)
++ goto err;
++ ASN1_INTEGER_free(aor->u.range->min);
++ aor->u.range->min = min;
++ ASN1_INTEGER_free(aor->u.range->max);
++ aor->u.range->max = max;
++ }
++ if (!(sk_ASIdOrRange_push((*choice)->u.asIdsOrRanges, aor)))
++ goto err;
++ return 1;
++
++ err:
++ ASIdOrRange_free(aor);
++ return 0;
++}
++
++/*
++ * Extract min and max values from an ASIdOrRange.
++ */
++static void extract_min_max(ASIdOrRange *aor,
++ ASN1_INTEGER **min,
++ ASN1_INTEGER **max)
++{
++ assert(aor != NULL && min != NULL && max != NULL);
++ switch (aor->type) {
++ case ASIdOrRange_id:
++ *min = aor->u.id;
++ *max = aor->u.id;
++ return;
++ case ASIdOrRange_range:
++ *min = aor->u.range->min;
++ *max = aor->u.range->max;
++ return;
++ }
++}
++
++/*
++ * Check whether an ASIdentifierChoice is in canonical form.
++ */
++static int ASIdentifierChoice_is_canonical(ASIdentifierChoice *choice)
++{
++ ASN1_INTEGER *a_max_plus_one = NULL;
++ BIGNUM *bn = NULL;
++ int i, ret = 0;
++
++ /*
++ * Empty element or inheritance is canonical.
++ */
++ if (choice == NULL || choice->type == ASIdentifierChoice_inherit)
++ return 1;
++
++ /*
++ * If not a list, or if empty list, it's broken.
++ */
++ if (choice->type != ASIdentifierChoice_asIdsOrRanges ||
++ sk_ASIdOrRange_num(choice->u.asIdsOrRanges) == 0)
++ return 0;
++
++ /*
++ * It's a list, check it.
++ */
++ for (i = 0; i < sk_ASIdOrRange_num(choice->u.asIdsOrRanges) - 1; i++) {
++ ASIdOrRange *a = sk_ASIdOrRange_value(choice->u.asIdsOrRanges, i);
++ ASIdOrRange *b = sk_ASIdOrRange_value(choice->u.asIdsOrRanges, i + 1);
++ ASN1_INTEGER *a_min, *a_max, *b_min, *b_max;
++
++ extract_min_max(a, &a_min, &a_max);
++ extract_min_max(b, &b_min, &b_max);
++
++ /*
++ * Punt misordered list, overlapping start, or inverted range.
++ */
++ if (ASN1_INTEGER_cmp(a_min, b_min) >= 0 ||
++ ASN1_INTEGER_cmp(a_min, a_max) > 0 ||
++ ASN1_INTEGER_cmp(b_min, b_max) > 0)
++ goto done;
++
++ /*
++ * Calculate a_max + 1 to check for adjacency.
++ */
++ if ((bn == NULL && (bn = BN_new()) == NULL) ||
++ ASN1_INTEGER_to_BN(a_max, bn) == NULL ||
++ !BN_add_word(bn, 1) ||
++ (a_max_plus_one = BN_to_ASN1_INTEGER(bn, a_max_plus_one)) == NULL) {
++ X509V3err(X509V3_F_ASIDENTIFIERCHOICE_IS_CANONICAL,
++ ERR_R_MALLOC_FAILURE);
++ goto done;
++ }
++
++ /*
++ * Punt if adjacent or overlapping.
++ */
++ if (ASN1_INTEGER_cmp(a_max_plus_one, b_min) >= 0)
++ goto done;
++ }
++
++ ret = 1;
++
++ done:
++ ASN1_INTEGER_free(a_max_plus_one);
++ BN_free(bn);
++ return ret;
++}
++
++/*
++ * Check whether an ASIdentifier extension is in canonical form.
++ */
++int v3_asid_is_canonical(ASIdentifiers *asid)
++{
++ return (asid == NULL ||
++ (ASIdentifierChoice_is_canonical(asid->asnum) ||
++ ASIdentifierChoice_is_canonical(asid->rdi)));
++}
++
++/*
++ * Whack an ASIdentifierChoice into canonical form.
++ */
++static int ASIdentifierChoice_canonize(ASIdentifierChoice *choice)
++{
++ ASN1_INTEGER *a_max_plus_one = NULL;
++ BIGNUM *bn = NULL;
++ int i, ret = 0;
++
++ /*
++ * Nothing to do for empty element or inheritance.
++ */
++ if (choice == NULL || choice->type == ASIdentifierChoice_inherit)
++ return 1;
++
++ /*
++ * We have a list. Sort it.
++ */
++ assert(choice->type == ASIdentifierChoice_asIdsOrRanges);
++ sk_ASIdOrRange_sort(choice->u.asIdsOrRanges);
++
++ /*
++ * Now check for errors and suboptimal encoding, rejecting the
++ * former and fixing the latter.
++ */
++ for (i = 0; i < sk_ASIdOrRange_num(choice->u.asIdsOrRanges) - 1; i++) {
++ ASIdOrRange *a = sk_ASIdOrRange_value(choice->u.asIdsOrRanges, i);
++ ASIdOrRange *b = sk_ASIdOrRange_value(choice->u.asIdsOrRanges, i + 1);
++ ASN1_INTEGER *a_min, *a_max, *b_min, *b_max;
++
++ extract_min_max(a, &a_min, &a_max);
++ extract_min_max(b, &b_min, &b_max);
++
++ /*
++ * Make sure we're properly sorted (paranoia).
++ */
++ assert(ASN1_INTEGER_cmp(a_min, b_min) <= 0);
++
++ /*
++ * Check for overlaps.
++ */
++ if (ASN1_INTEGER_cmp(a_max, b_min) >= 0) {
++ X509V3err(X509V3_F_ASIDENTIFIERCHOICE_CANONIZE,
++ X509V3_R_EXTENSION_VALUE_ERROR);
++ goto done;
++ }
++
++ /*
++ * Calculate a_max + 1 to check for adjacency.
++ */
++ if ((bn == NULL && (bn = BN_new()) == NULL) ||
++ ASN1_INTEGER_to_BN(a_max, bn) == NULL ||
++ !BN_add_word(bn, 1) ||
++ (a_max_plus_one = BN_to_ASN1_INTEGER(bn, a_max_plus_one)) == NULL) {
++ X509V3err(X509V3_F_ASIDENTIFIERCHOICE_CANONIZE, ERR_R_MALLOC_FAILURE);
++ goto done;
++ }
++
++ /*
++ * If a and b are adjacent, merge them.
++ */
++ if (ASN1_INTEGER_cmp(a_max_plus_one, b_min) == 0) {
++ ASRange *r;
++ switch (a->type) {
++ case ASIdOrRange_id:
++ if ((r = OPENSSL_malloc(sizeof(ASRange))) == NULL) {
++ X509V3err(X509V3_F_ASIDENTIFIERCHOICE_CANONIZE,
++ ERR_R_MALLOC_FAILURE);
++ goto done;
++ }
++ r->min = a_min;
++ r->max = b_max;
++ a->type = ASIdOrRange_range;
++ a->u.range = r;
++ break;
++ case ASIdOrRange_range:
++ ASN1_INTEGER_free(a->u.range->max);
++ a->u.range->max = b_max;
++ break;
++ }
++ switch (b->type) {
++ case ASIdOrRange_id:
++ b->u.id = NULL;
++ break;
++ case ASIdOrRange_range:
++ b->u.range->max = NULL;
++ break;
++ }
++ ASIdOrRange_free(b);
++ sk_ASIdOrRange_delete(choice->u.asIdsOrRanges, i + 1);
++ i--;
++ continue;
++ }
++ }
++
++ assert(ASIdentifierChoice_is_canonical(choice)); /* Paranoia */
++
++ ret = 1;
++
++ done:
++ ASN1_INTEGER_free(a_max_plus_one);
++ BN_free(bn);
++ return ret;
++}
++
++/*
++ * Whack an ASIdentifier extension into canonical form.
++ */
++int v3_asid_canonize(ASIdentifiers *asid)
++{
++ return (asid == NULL ||
++ (ASIdentifierChoice_canonize(asid->asnum) &&
++ ASIdentifierChoice_canonize(asid->rdi)));
++}
++
++/*
++ * v2i method for an ASIdentifier extension.
++ */
++static void *v2i_ASIdentifiers(struct v3_ext_method *method,
++ struct v3_ext_ctx *ctx,
++ STACK_OF(CONF_VALUE) *values)
++{
++ ASIdentifiers *asid = NULL;
++ int i;
++
++ if ((asid = ASIdentifiers_new()) == NULL) {
++ X509V3err(X509V3_F_V2I_ASIDENTIFIERS, ERR_R_MALLOC_FAILURE);
++ return NULL;
++ }
++
++ for (i = 0; i < sk_CONF_VALUE_num(values); i++) {
++ CONF_VALUE *val = sk_CONF_VALUE_value(values, i);
++ ASIdentifierChoice **choice;
++ ASN1_INTEGER *min = NULL, *max = NULL;
++ int i1, i2, i3, is_range;
++
++ /*
++ * Figure out whether this is an AS or an RDI.
++ */
++ if ( !name_cmp(val->name, "AS")) {
++ choice = &asid->asnum;
++ } else if (!name_cmp(val->name, "RDI")) {
++ choice = &asid->rdi;
++ } else {
++ X509V3err(X509V3_F_V2I_ASIDENTIFIERS, X509V3_R_EXTENSION_NAME_ERROR);
++ X509V3_conf_err(val);
++ goto err;
++ }
++
++ /*
++ * Handle inheritance.
++ */
++ if (!strcmp(val->value, "inherit")) {
++ if (asid_add_inherit(choice))
++ continue;
++ X509V3err(X509V3_F_V2I_ASIDENTIFIERS, X509V3_R_INVALID_INHERITANCE);
++ X509V3_conf_err(val);
++ goto err;
++ }
++
++ /*
++ * Number, range, or mistake, pick it apart and figure out which.
++ */
++ i1 = strspn(val->value, "0123456789");
++ if (val->value[i1] == '\0') {
++ is_range = 0;
++ } else {
++ is_range = 1;
++ i2 = i1 + strspn(val->value + i1, " \t");
++ if (val->value[i2] != '-') {
++ X509V3err(X509V3_F_V2I_ASIDENTIFIERS, X509V3_R_INVALID_ASNUMBER);
++ X509V3_conf_err(val);
++ goto err;
++ }
++ i2++;
++ i2 = i2 + strspn(val->value + i2, " \t");
++ i3 = i2 + strspn(val->value + i2, "0123456789");
++ if (val->value[i3] != '\0') {
++ X509V3err(X509V3_F_V2I_ASIDENTIFIERS, X509V3_R_INVALID_ASRANGE);
++ X509V3_conf_err(val);
++ goto err;
++ }
++ }
++
++ /*
++ * Syntax is ok, read and add it.
++ */
++ if (!is_range) {
++ if (!X509V3_get_value_int(val, &min)) {
++ X509V3err(X509V3_F_V2I_ASIDENTIFIERS, ERR_R_MALLOC_FAILURE);
++ goto err;
++ }
++ } else {
++ char *s = BUF_strdup(val->value);
++ if (s == NULL) {
++ X509V3err(X509V3_F_V2I_ASIDENTIFIERS, ERR_R_MALLOC_FAILURE);
++ goto err;
++ }
++ s[i1] = '\0';
++ min = s2i_ASN1_INTEGER(NULL, s);
++ max = s2i_ASN1_INTEGER(NULL, s + i2);
++ OPENSSL_free(s);
++ if (min == NULL || max == NULL) {
++ ASN1_INTEGER_free(min);
++ ASN1_INTEGER_free(max);
++ X509V3err(X509V3_F_V2I_ASIDENTIFIERS, ERR_R_MALLOC_FAILURE);
++ goto err;
++ }
++ }
++ if (!asid_add_id_or_range(choice, min, max)) {
++ ASN1_INTEGER_free(min);
++ ASN1_INTEGER_free(max);
++ X509V3err(X509V3_F_V2I_ASIDENTIFIERS, ERR_R_MALLOC_FAILURE);
++ goto err;
++ }
++ }
++
++ /*
++ * Canonize the result, then we're done.
++ */
++ if (!v3_asid_canonize(asid))
++ goto err;
++ return asid;
++
++ err:
++ ASIdentifiers_free(asid);
++ return NULL;
++}
++
++/*
++ * OpenSSL dispatch.
++ */
++X509V3_EXT_METHOD v3_asid = {
++ NID_sbgp_autonomousSysNum, /* nid */
++ 0, /* flags */
++ ASN1_ITEM_ref(ASIdentifiers), /* template */
++ 0, 0, 0, 0, /* old functions, ignored */
++ 0, /* i2s */
++ 0, /* s2i */
++ 0, /* i2v */
++ v2i_ASIdentifiers, /* v2i */
++ i2r_ASIdentifiers, /* i2r */
++ 0, /* r2i */
++ NULL /* extension-specific data */
++};
++
++/*
++ * Figure out whether extension uses inheritance.
++ */
++int v3_asid_inherits(ASIdentifiers *asid)
++{
++ return (asid != NULL &&
++ ((asid->asnum != NULL &&
++ asid->asnum->type == ASIdentifierChoice_inherit) ||
++ (asid->rdi != NULL &&
++ asid->rdi->type == ASIdentifierChoice_inherit)));
++}
++
++/*
++ * Figure out whether parent contains child.
++ */
++static int asid_contains(ASIdOrRanges *parent, ASIdOrRanges *child)
++{
++ ASN1_INTEGER *p_min, *p_max, *c_min, *c_max;
++ int p, c;
++
++ if (child == NULL || parent == child)
++ return 1;
++ if (parent == NULL)
++ return 0;
++
++ p = 0;
++ for (c = 0; c < sk_ASIdOrRange_num(child); c++) {
++ extract_min_max(sk_ASIdOrRange_value(child, c), &c_min, &c_max);
++ for (;; p++) {
++ if (p >= sk_ASIdOrRange_num(parent))
++ return 0;
++ extract_min_max(sk_ASIdOrRange_value(parent, p), &p_min, &p_max);
++ if (ASN1_INTEGER_cmp(p_max, c_max) < 0)
++ continue;
++ if (ASN1_INTEGER_cmp(p_min, c_min) > 0)
++ return 0;
++ break;
++ }
++ }
++
++ return 1;
++}
++
++/*
++ * Test whether a is a subet of b.
++ */
++int v3_asid_subset(ASIdentifiers *a, ASIdentifiers *b)
++{
++ return (a == NULL ||
++ a == b ||
++ (b != NULL &&
++ !v3_asid_inherits(a) &&
++ !v3_asid_inherits(b) &&
++ asid_contains(b->asnum->u.asIdsOrRanges,
++ a->asnum->u.asIdsOrRanges) &&
++ asid_contains(b->rdi->u.asIdsOrRanges,
++ a->rdi->u.asIdsOrRanges)));
++}
++
++/*
++ * Validation error handling via callback.
++ */
++#define validation_err(_err_) \
++ do { \
++ if (ctx != NULL) { \
++ ctx->error = _err_; \
++ ctx->error_depth = i; \
++ ctx->current_cert = x; \
++ ret = ctx->verify_cb(0, ctx); \
++ } else { \
++ ret = 0; \
++ } \
++ if (!ret) \
++ goto done; \
++ } while (0)
++
++/*
++ * Core code for RFC 3779 3.3 path validation.
++ */
++static int v3_asid_validate_path_internal(X509_STORE_CTX *ctx,
++ STACK_OF(X509) *chain,
++ ASIdentifiers *ext)
++{
++ ASIdOrRanges *child_as = NULL, *child_rdi = NULL;
++ int i, ret = 1, inherit_as = 0, inherit_rdi = 0;
++ X509 *x;
++
++ assert(chain != NULL && sk_X509_num(chain) > 0);
++ assert(ctx != NULL || ext != NULL);
++ assert(ctx == NULL || ctx->verify_cb != NULL);
++
++ /*
++ * Figure out where to start. If we don't have an extension to
++ * check, we're done. Otherwise, check canonical form and
++ * set up for walking up the chain.
++ */
++ if (ext != NULL) {
++ i = -1;
++ } else {
++ i = 0;
++ x = sk_X509_value(chain, i);
++ assert(x != NULL);
++ if ((ext = x->rfc3779_asid) == NULL)
++ goto done;
++ }
++ if (!v3_asid_is_canonical(ext))
++ validation_err(X509_V_ERR_INVALID_EXTENSION);
++ if (ext->asnum != NULL) {
++ switch (ext->asnum->type) {
++ case ASIdentifierChoice_inherit:
++ inherit_as = 1;
++ break;
++ case ASIdentifierChoice_asIdsOrRanges:
++ child_as = ext->asnum->u.asIdsOrRanges;
++ break;
++ }
++ }
++ if (ext->rdi != NULL) {
++ switch (ext->rdi->type) {
++ case ASIdentifierChoice_inherit:
++ inherit_rdi = 1;
++ break;
++ case ASIdentifierChoice_asIdsOrRanges:
++ child_rdi = ext->rdi->u.asIdsOrRanges;
++ break;
++ }
++ }
++
++ /*
++ * Now walk up the chain. Extensions must be in canonical form, no
++ * cert may list resources that its parent doesn't list.
++ */
++ for (i++; i < sk_X509_num(chain); i++) {
++ x = sk_X509_value(chain, i);
++ assert(x != NULL);
++ if (x->rfc3779_asid == NULL) {
++ if (child_as != NULL || child_rdi != NULL)
++ validation_err(X509_V_ERR_UNNESTED_RESOURCE);
++ continue;
++ }
++ if (!v3_asid_is_canonical(x->rfc3779_asid))
++ validation_err(X509_V_ERR_INVALID_EXTENSION);
++ if (x->rfc3779_asid->asnum == NULL && child_as != NULL) {
++ validation_err(X509_V_ERR_UNNESTED_RESOURCE);
++ child_as = NULL;
++ inherit_as = 0;
++ }
++ if (x->rfc3779_asid->asnum != NULL &&
++ x->rfc3779_asid->asnum->type == ASIdentifierChoice_asIdsOrRanges) {
++ if (inherit_as ||
++ asid_contains(x->rfc3779_asid->asnum->u.asIdsOrRanges, child_as)) {
++ child_as = x->rfc3779_asid->asnum->u.asIdsOrRanges;
++ inherit_as = 0;
++ } else {
++ validation_err(X509_V_ERR_UNNESTED_RESOURCE);
++ }
++ }
++ if (x->rfc3779_asid->rdi == NULL && child_rdi != NULL) {
++ validation_err(X509_V_ERR_UNNESTED_RESOURCE);
++ child_rdi = NULL;
++ inherit_rdi = 0;
++ }
++ if (x->rfc3779_asid->rdi != NULL &&
++ x->rfc3779_asid->rdi->type == ASIdentifierChoice_asIdsOrRanges) {
++ if (inherit_rdi ||
++ asid_contains(x->rfc3779_asid->rdi->u.asIdsOrRanges, child_rdi)) {
++ child_rdi = x->rfc3779_asid->rdi->u.asIdsOrRanges;
++ inherit_rdi = 0;
++ } else {
++ validation_err(X509_V_ERR_UNNESTED_RESOURCE);
++ }
++ }
++ }
++
++ /*
++ * Trust anchor can't inherit.
++ */
++ if (x->rfc3779_asid != NULL) {
++ if (x->rfc3779_asid->asnum != NULL &&
++ x->rfc3779_asid->asnum->type == ASIdentifierChoice_inherit)
++ validation_err(X509_V_ERR_UNNESTED_RESOURCE);
++ if (x->rfc3779_asid->rdi != NULL &&
++ x->rfc3779_asid->rdi->type == ASIdentifierChoice_inherit)
++ validation_err(X509_V_ERR_UNNESTED_RESOURCE);
++ }
++
++ done:
++ return ret;
++}
++
++#undef validation_err
++
++/*
++ * RFC 3779 3.3 path validation -- called from X509_verify_cert().
++ */
++int v3_asid_validate_path(X509_STORE_CTX *ctx)
++{
++ return v3_asid_validate_path_internal(ctx, ctx->chain, NULL);
++}
++
++/*
++ * RFC 3779 3.3 path validation of an extension.
++ * Test whether chain covers extension.
++ */
++int v3_asid_validate_resource_set(STACK_OF(X509) *chain,
++ ASIdentifiers *ext,
++ int allow_inheritance)
++{
++ if (ext == NULL)
++ return 1;
++ if (chain == NULL || sk_X509_num(chain) == 0)
++ return 0;
++ if (!allow_inheritance && v3_asid_inherits(ext))
++ return 0;
++ return v3_asid_validate_path_internal(NULL, chain, ext);
++}
+
+Index: crypto/x509v3/Makefile
+===================================================================
+--- crypto/x509v3/Makefile (.../vendor/0.9.8b) (revision 251)
++++ crypto/x509v3/Makefile (.../trunk) (revision 251)
+@@ -21,12 +21,14 @@
+ v3_prn.c v3_utl.c v3err.c v3_genn.c v3_alt.c v3_skey.c v3_akey.c v3_pku.c \
+ v3_int.c v3_enum.c v3_sxnet.c v3_cpols.c v3_crld.c v3_purp.c v3_info.c \
+ v3_ocsp.c v3_akeya.c v3_pmaps.c v3_pcons.c v3_ncons.c v3_pcia.c v3_pci.c \
+-pcy_cache.c pcy_node.c pcy_data.c pcy_map.c pcy_tree.c pcy_lib.c
++pcy_cache.c pcy_node.c pcy_data.c pcy_map.c pcy_tree.c pcy_lib.c \
++v3_asid.c v3_addr.c
+ LIBOBJ= v3_bcons.o v3_bitst.o v3_conf.o v3_extku.o v3_ia5.o v3_lib.o \
+ v3_prn.o v3_utl.o v3err.o v3_genn.o v3_alt.o v3_skey.o v3_akey.o v3_pku.o \
+ v3_int.o v3_enum.o v3_sxnet.o v3_cpols.o v3_crld.o v3_purp.o v3_info.o \
+ v3_ocsp.o v3_akeya.o v3_pmaps.o v3_pcons.o v3_ncons.o v3_pcia.o v3_pci.o \
+-pcy_cache.o pcy_node.o pcy_data.o pcy_map.o pcy_tree.o pcy_lib.o
++pcy_cache.o pcy_node.o pcy_data.o pcy_map.o pcy_tree.o pcy_lib.o \
++v3_asid.o v3_addr.o
+
+ SRC= $(LIBSRC)
+
+@@ -166,6 +168,20 @@
+ pcy_tree.o: ../../include/openssl/symhacks.h ../../include/openssl/x509.h
+ pcy_tree.o: ../../include/openssl/x509_vfy.h ../../include/openssl/x509v3.h
+ pcy_tree.o: ../cryptlib.h pcy_int.h pcy_tree.c
++v3_addr.o: ../../e_os.h ../../include/openssl/asn1.h
++v3_addr.o: ../../include/openssl/asn1t.h ../../include/openssl/bio.h
++v3_addr.o: ../../include/openssl/buffer.h ../../include/openssl/conf.h
++v3_addr.o: ../../include/openssl/crypto.h ../../include/openssl/e_os2.h
++v3_addr.o: ../../include/openssl/ec.h ../../include/openssl/ecdh.h
++v3_addr.o: ../../include/openssl/ecdsa.h ../../include/openssl/err.h
++v3_addr.o: ../../include/openssl/evp.h ../../include/openssl/lhash.h
++v3_addr.o: ../../include/openssl/obj_mac.h ../../include/openssl/objects.h
++v3_addr.o: ../../include/openssl/opensslconf.h ../../include/openssl/opensslv.h
++v3_addr.o: ../../include/openssl/ossl_typ.h ../../include/openssl/pkcs7.h
++v3_addr.o: ../../include/openssl/safestack.h ../../include/openssl/sha.h
++v3_addr.o: ../../include/openssl/stack.h ../../include/openssl/symhacks.h
++v3_addr.o: ../../include/openssl/x509.h ../../include/openssl/x509_vfy.h
++v3_addr.o: ../../include/openssl/x509v3.h ../cryptlib.h v3_addr.c
+ v3_akey.o: ../../e_os.h ../../include/openssl/asn1.h
+ v3_akey.o: ../../include/openssl/asn1t.h ../../include/openssl/bio.h
+ v3_akey.o: ../../include/openssl/buffer.h ../../include/openssl/conf.h
+@@ -208,6 +224,21 @@
+ v3_alt.o: ../../include/openssl/stack.h ../../include/openssl/symhacks.h
+ v3_alt.o: ../../include/openssl/x509.h ../../include/openssl/x509_vfy.h
+ v3_alt.o: ../../include/openssl/x509v3.h ../cryptlib.h v3_alt.c
++v3_asid.o: ../../e_os.h ../../include/openssl/asn1.h
++v3_asid.o: ../../include/openssl/asn1t.h ../../include/openssl/bio.h
++v3_asid.o: ../../include/openssl/bn.h ../../include/openssl/buffer.h
++v3_asid.o: ../../include/openssl/conf.h ../../include/openssl/crypto.h
++v3_asid.o: ../../include/openssl/e_os2.h ../../include/openssl/ec.h
++v3_asid.o: ../../include/openssl/ecdh.h ../../include/openssl/ecdsa.h
++v3_asid.o: ../../include/openssl/err.h ../../include/openssl/evp.h
++v3_asid.o: ../../include/openssl/lhash.h ../../include/openssl/obj_mac.h
++v3_asid.o: ../../include/openssl/objects.h ../../include/openssl/opensslconf.h
++v3_asid.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h
++v3_asid.o: ../../include/openssl/pkcs7.h ../../include/openssl/safestack.h
++v3_asid.o: ../../include/openssl/sha.h ../../include/openssl/stack.h
++v3_asid.o: ../../include/openssl/symhacks.h ../../include/openssl/x509.h
++v3_asid.o: ../../include/openssl/x509_vfy.h ../../include/openssl/x509v3.h
++v3_asid.o: ../cryptlib.h v3_asid.c
+ v3_bcons.o: ../../e_os.h ../../include/openssl/asn1.h
+ v3_bcons.o: ../../include/openssl/asn1t.h ../../include/openssl/bio.h
+ v3_bcons.o: ../../include/openssl/buffer.h ../../include/openssl/conf.h
+Index: crypto/x509v3/v3err.c
+===================================================================
+--- crypto/x509v3/v3err.c (.../vendor/0.9.8b) (revision 251)
++++ crypto/x509v3/v3err.c (.../trunk) (revision 251)
+@@ -70,6 +70,8 @@
+
+ static ERR_STRING_DATA X509V3_str_functs[]=
+ {
++{ERR_FUNC(X509V3_F_ASIDENTIFIERCHOICE_CANONIZE), "ASIDENTIFIERCHOICE_CANONIZE"},
++{ERR_FUNC(X509V3_F_ASIDENTIFIERCHOICE_IS_CANONICAL), "ASIDENTIFIERCHOICE_IS_CANONICAL"},
+ {ERR_FUNC(X509V3_F_COPY_EMAIL), "COPY_EMAIL"},
+ {ERR_FUNC(X509V3_F_COPY_ISSUER), "COPY_ISSUER"},
+ {ERR_FUNC(X509V3_F_DO_DIRNAME), "DO_DIRNAME"},
+@@ -99,6 +101,7 @@
+ {ERR_FUNC(X509V3_F_SXNET_ADD_ID_ULONG), "SXNET_add_id_ulong"},
+ {ERR_FUNC(X509V3_F_SXNET_GET_ID_ASC), "SXNET_get_id_asc"},
+ {ERR_FUNC(X509V3_F_SXNET_GET_ID_ULONG), "SXNET_get_id_ulong"},
++{ERR_FUNC(X509V3_F_V2I_ASIDENTIFIERS), "V2I_ASIDENTIFIERS"},
+ {ERR_FUNC(X509V3_F_V2I_ASN1_BIT_STRING), "V2I_ASN1_BIT_STRING"},
+ {ERR_FUNC(X509V3_F_V2I_AUTHORITY_INFO_ACCESS), "V2I_AUTHORITY_INFO_ACCESS"},
+ {ERR_FUNC(X509V3_F_V2I_AUTHORITY_KEYID), "V2I_AUTHORITY_KEYID"},
+@@ -107,11 +110,13 @@
+ {ERR_FUNC(X509V3_F_V2I_EXTENDED_KEY_USAGE), "V2I_EXTENDED_KEY_USAGE"},
+ {ERR_FUNC(X509V3_F_V2I_GENERAL_NAMES), "v2i_GENERAL_NAMES"},
+ {ERR_FUNC(X509V3_F_V2I_GENERAL_NAME_EX), "v2i_GENERAL_NAME_ex"},
++{ERR_FUNC(X509V3_F_V2I_IPADDRBLOCKS), "V2I_IPADDRBLOCKS"},
+ {ERR_FUNC(X509V3_F_V2I_ISSUER_ALT), "V2I_ISSUER_ALT"},
+ {ERR_FUNC(X509V3_F_V2I_NAME_CONSTRAINTS), "V2I_NAME_CONSTRAINTS"},
+ {ERR_FUNC(X509V3_F_V2I_POLICY_CONSTRAINTS), "V2I_POLICY_CONSTRAINTS"},
+ {ERR_FUNC(X509V3_F_V2I_POLICY_MAPPINGS), "V2I_POLICY_MAPPINGS"},
+ {ERR_FUNC(X509V3_F_V2I_SUBJECT_ALT), "V2I_SUBJECT_ALT"},
++{ERR_FUNC(X509V3_F_V3_ADDR_VALIDATE_PATH_INTERNAL), "V3_ADDR_VALIDATE_PATH_INTERNAL"},
+ {ERR_FUNC(X509V3_F_V3_GENERIC_EXTENSION), "V3_GENERIC_EXTENSION"},
+ {ERR_FUNC(X509V3_F_X509V3_ADD1_I2D), "X509V3_add1_i2d"},
+ {ERR_FUNC(X509V3_F_X509V3_ADD_VALUE), "X509V3_add_value"},
+@@ -149,8 +154,12 @@
+ {ERR_REASON(X509V3_R_ILLEGAL_EMPTY_EXTENSION),"illegal empty extension"},
+ {ERR_REASON(X509V3_R_ILLEGAL_HEX_DIGIT) ,"illegal hex digit"},
+ {ERR_REASON(X509V3_R_INCORRECT_POLICY_SYNTAX_TAG),"incorrect policy syntax tag"},
++{ERR_REASON(X509V3_R_INVALID_ASNUMBER) ,"invalid asnumber"},
++{ERR_REASON(X509V3_R_INVALID_ASRANGE) ,"invalid asrange"},
+ {ERR_REASON(X509V3_R_INVALID_BOOLEAN_STRING),"invalid boolean string"},
+ {ERR_REASON(X509V3_R_INVALID_EXTENSION_STRING),"invalid extension string"},
++{ERR_REASON(X509V3_R_INVALID_INHERITANCE),"invalid inheritance"},
++{ERR_REASON(X509V3_R_INVALID_IPADDRESS) ,"invalid ipaddress"},
+ {ERR_REASON(X509V3_R_INVALID_NAME) ,"invalid name"},
+ {ERR_REASON(X509V3_R_INVALID_NULL_ARGUMENT),"invalid null argument"},
+ {ERR_REASON(X509V3_R_INVALID_NULL_NAME) ,"invalid null name"},
+@@ -162,6 +171,7 @@
+ {ERR_REASON(X509V3_R_INVALID_POLICY_IDENTIFIER),"invalid policy identifier"},
+ {ERR_REASON(X509V3_R_INVALID_PROXY_POLICY_SETTING),"invalid proxy policy setting"},
+ {ERR_REASON(X509V3_R_INVALID_PURPOSE) ,"invalid purpose"},
++{ERR_REASON(X509V3_R_INVALID_SAFI) ,"invalid safi"},
+ {ERR_REASON(X509V3_R_INVALID_SECTION) ,"invalid section"},
+ {ERR_REASON(X509V3_R_INVALID_SYNTAX) ,"invalid syntax"},
+ {ERR_REASON(X509V3_R_ISSUER_DECODE_ERROR),"issuer decode error"},
+Index: crypto/x509v3/pcy_tree.c
+===================================================================
+--- crypto/x509v3/pcy_tree.c (.../vendor/0.9.8b) (revision 251)
++++ crypto/x509v3/pcy_tree.c (.../trunk) (revision 251)
+@@ -628,6 +628,16 @@
+ /* Tree OK: continue */
+
+ case 1:
++ if (!tree)
++ /*
++ * tree_init() returns success and a null tree
++ * if it's just looking at a trust anchor.
++ * I'm not sure that returning success here is
++ * correct, but I'm sure that reporting this
++ * as an internal error which our caller
++ * interprets as a malloc failure is wrong.
++ */
++ return 1;
+ break;
+ }
+
+Index: crypto/x509v3/v3_addr.c
+===================================================================
+--- crypto/x509v3/v3_addr.c (.../vendor/0.9.8b) (revision 0)
++++ crypto/x509v3/v3_addr.c (.../trunk) (revision 251)
+@@ -0,0 +1,1214 @@
++/*
++ * Copyright (C) 2006 American Registry for Internet Numbers ("ARIN")
++ *
++ * Permission to use, copy, modify, and distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ARIN DISCLAIMS ALL WARRANTIES WITH
++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS. IN NO EVENT SHALL ARIN BE LIABLE FOR ANY SPECIAL, DIRECT,
++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/* $Id$ */
++
++/*
++ * Implementation of RFC 3779 section 2.2.
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <assert.h>
++#include "cryptlib.h"
++#include <openssl/conf.h>
++#include <openssl/asn1.h>
++#include <openssl/asn1t.h>
++#include <openssl/x509v3.h>
++
++/*
++ * OpenSSL ASN.1 template translation of RFC 3779 2.2.3.
++ */
++
++ASN1_SEQUENCE(IPAddressRange) = {
++ ASN1_SIMPLE(IPAddressRange, min, ASN1_BIT_STRING),
++ ASN1_SIMPLE(IPAddressRange, max, ASN1_BIT_STRING)
++} ASN1_SEQUENCE_END(IPAddressRange)
++
++ASN1_CHOICE(IPAddressOrRange) = {
++ ASN1_SIMPLE(IPAddressOrRange, u.addressPrefix, ASN1_BIT_STRING),
++ ASN1_SIMPLE(IPAddressOrRange, u.addressRange, IPAddressRange)
++} ASN1_CHOICE_END(IPAddressOrRange)
++
++ASN1_CHOICE(IPAddressChoice) = {
++ ASN1_SIMPLE(IPAddressChoice, u.inherit, ASN1_NULL),
++ ASN1_SEQUENCE_OF(IPAddressChoice, u.addressesOrRanges, IPAddressOrRange)
++} ASN1_CHOICE_END(IPAddressChoice)
++
++ASN1_SEQUENCE(IPAddressFamily) = {
++ ASN1_SIMPLE(IPAddressFamily, addressFamily, ASN1_OCTET_STRING),
++ ASN1_SIMPLE(IPAddressFamily, ipAddressChoice, IPAddressChoice)
++} ASN1_SEQUENCE_END(IPAddressFamily)
++
++ASN1_ITEM_TEMPLATE(IPAddrBlocks) =
++ ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0,
++ IPAddrBlocks, IPAddressFamily)
++ASN1_ITEM_TEMPLATE_END(IPAddrBlocks)
++
++IMPLEMENT_ASN1_FUNCTIONS(IPAddressRange)
++IMPLEMENT_ASN1_FUNCTIONS(IPAddressOrRange)
++IMPLEMENT_ASN1_FUNCTIONS(IPAddressChoice)
++IMPLEMENT_ASN1_FUNCTIONS(IPAddressFamily)
++
++/*
++ * How much buffer space do we need for a raw address?
++ */
++#define ADDR_RAW_BUF_LEN 16
++
++/*
++ * What's the address length associated with this AFI?
++ */
++static int length_from_afi(const unsigned afi)
++{
++ switch (afi) {
++ case IANA_AFI_IPV4:
++ return 4;
++ case IANA_AFI_IPV6:
++ return 16;
++ default:
++ return 0;
++ }
++}
++
++/*
++ * Extract the AFI from an IPAddressFamily.
++ */
++static unsigned afi_from_addressfamily(const IPAddressFamily *f)
++{
++ return (f != NULL && f->addressFamily != NULL && f->addressFamily->data
++ ? ((f->addressFamily->data[0] << 8) |
++ (f->addressFamily->data[1]))
++ : 0);
++}
++
++/*
++ * Expand the bitstring form of an address into a raw byte array.
++ * At the moment this is coded for simplicity, not speed.
++ */
++static void addr_expand(unsigned char *addr,
++ const ASN1_BIT_STRING *bs,
++ const int length,
++ const unsigned char fill)
++{
++ assert(bs->length >= 0 && bs->length <= length);
++ if (bs->length > 0) {
++ memcpy(addr, bs->data, bs->length);
++ if ((bs->flags & 7) != 0) {
++ unsigned char mask = 0xFF >> (8 - (bs->flags & 7));
++ if (fill == 0)
++ addr[bs->length - 1] &= ~mask;
++ else
++ addr[bs->length - 1] |= mask;
++ }
++ }
++ memset(addr + bs->length, fill, length - bs->length);
++}
++
++/*
++ * Extract the prefix length from a bitstring.
++ */
++#define addr_prefixlen(bs) ((int) ((bs)->length * 8 - ((bs)->flags & 7)))
++
++/*
++ * i2r handler for one address bitstring.
++ */
++static int i2r_address(BIO *out,
++ const unsigned afi,
++ const unsigned char fill,
++ const ASN1_BIT_STRING *bs)
++{
++ unsigned char addr[ADDR_RAW_BUF_LEN];
++ int i, n;
++
++ switch (afi) {
++ case IANA_AFI_IPV4:
++ addr_expand(addr, bs, 4, fill);
++ BIO_printf(out, "%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]);
++ break;
++ case IANA_AFI_IPV6:
++ addr_expand(addr, bs, 16, fill);
++ for (n = 16; n > 1 && addr[n-1] == 0x00 && addr[n-2] == 0x00; n -= 2)
++ ;
++ for (i = 0; i < n; i += 2)
++ BIO_printf(out, "%x%s", (addr[i] << 8) | addr[i+1], (i < 14 ? ":" : ""));
++ if (i < 16)
++ BIO_puts(out, ":");
++ break;
++ default:
++ for (i = 0; i < bs->length; i++)
++ BIO_printf(out, "%s%02x", (i > 0 ? ":" : ""), bs->data[i]);
++ BIO_printf(out, "[%d]", (int) (bs->flags & 7));
++ break;
++ }
++ return 1;
++}
++
++/*
++ * i2r handler for a sequence of addresses and ranges.
++ */
++static int i2r_IPAddressOrRanges(BIO *out,
++ const int indent,
++ const IPAddressOrRanges *aors,
++ const unsigned afi)
++{
++ int i;
++ for (i = 0; i < sk_IPAddressOrRange_num(aors); i++) {
++ const IPAddressOrRange *aor = sk_IPAddressOrRange_value(aors, i);
++ BIO_printf(out, "%*s", indent, "");
++ switch (aor->type) {
++ case IPAddressOrRange_addressPrefix:
++ if (!i2r_address(out, afi, 0x00, aor->u.addressPrefix))
++ return 0;
++ BIO_printf(out, "/%d\n", addr_prefixlen(aor->u.addressPrefix));
++ continue;
++ case IPAddressOrRange_addressRange:
++ if (!i2r_address(out, afi, 0x00, aor->u.addressRange->min))
++ return 0;
++ BIO_puts(out, "-");
++ if (!i2r_address(out, afi, 0xFF, aor->u.addressRange->max))
++ return 0;
++ BIO_puts(out, "\n");
++ continue;
++ }
++ }
++ return 1;
++}
++
++/*
++ * i2r handler for an IPAddrBlocks extension.
++ */
++static int i2r_IPAddrBlocks(X509V3_EXT_METHOD *method,
++ void *ext,
++ BIO *out,
++ int indent)
++{
++ const IPAddrBlocks *addr = ext;
++ int i;
++ for (i = 0; i < sk_IPAddressFamily_num(addr); i++) {
++ IPAddressFamily *f = sk_IPAddressFamily_value(addr, i);
++ const unsigned afi = afi_from_addressfamily(f);
++ switch (afi) {
++ case IANA_AFI_IPV4:
++ BIO_printf(out, "%*sIPv4", indent, "");
++ break;
++ case IANA_AFI_IPV6:
++ BIO_printf(out, "%*sIPv6", indent, "");
++ break;
++ default:
++ BIO_printf(out, "%*sUnknown AFI %u", indent, "", afi);
++ break;
++ }
++ if (f->addressFamily->length > 2) {
++ switch (f->addressFamily->data[2]) {
++ case 1:
++ BIO_puts(out, " (Unicast)");
++ break;
++ case 2:
++ BIO_puts(out, " (Multicast)");
++ break;
++ case 3:
++ BIO_puts(out, " (Unicast/Multicast)");
++ break;
++ case 4:
++ BIO_puts(out, " (MPLS)");
++ break;
++ case 64:
++ BIO_puts(out, " (Tunnel)");
++ break;
++ case 65:
++ BIO_puts(out, " (VPLS)");
++ break;
++ case 66:
++ BIO_puts(out, " (BGP MDT)");
++ break;
++ case 128:
++ BIO_puts(out, " (MPLS-labeled VPN)");
++ break;
++ default:
++ BIO_printf(out, " (Unknown SAFI %u)",
++ (unsigned) f->addressFamily->data[2]);
++ break;
++ }
++ }
++ switch (f->ipAddressChoice->type) {
++ case IPAddressChoice_inherit:
++ BIO_puts(out, ": inherit\n");
++ break;
++ case IPAddressChoice_addressesOrRanges:
++ BIO_puts(out, ":\n");
++ if (!i2r_IPAddressOrRanges(out,
++ indent + 2,
++ f->ipAddressChoice->u.addressesOrRanges,
++ afi))
++ return 0;
++ break;
++ }
++ }
++ return 1;
++}
++
++/*
++ * Sort comparison function for a sequence of IPAddressOrRange
++ * elements.
++ */
++static int IPAddressOrRange_cmp(const IPAddressOrRange *a,
++ const IPAddressOrRange *b,
++ const int length)
++{
++ unsigned char addr_a[ADDR_RAW_BUF_LEN], addr_b[ADDR_RAW_BUF_LEN];
++ int prefixlen_a, prefixlen_b;
++ int r;
++
++ switch (a->type) {
++ case IPAddressOrRange_addressPrefix:
++ addr_expand(addr_a, a->u.addressPrefix, length, 0x00);
++ prefixlen_a = addr_prefixlen(a->u.addressPrefix);
++ break;
++ case IPAddressOrRange_addressRange:
++ addr_expand(addr_a, a->u.addressRange->min, length, 0x00);
++ prefixlen_a = length * 8;
++ break;
++ }
++
++ switch (b->type) {
++ case IPAddressOrRange_addressPrefix:
++ addr_expand(addr_b, b->u.addressPrefix, length, 0x00);
++ prefixlen_b = addr_prefixlen(b->u.addressPrefix);
++ break;
++ case IPAddressOrRange_addressRange:
++ addr_expand(addr_b, b->u.addressRange->min, length, 0x00);
++ prefixlen_b = length * 8;
++ break;
++ }
++
++ if ((r = memcmp(addr_a, addr_b, length)) != 0)
++ return r;
++ else
++ return prefixlen_a - prefixlen_b;
++}
++
++/*
++ * IPv4-specific closure over IPAddressOrRange_cmp, since sk_sort()
++ * comparision routines are only allowed two arguments.
++ */
++static int v4IPAddressOrRange_cmp(const IPAddressOrRange * const *a,
++ const IPAddressOrRange * const *b)
++{
++ return IPAddressOrRange_cmp(*a, *b, 4);
++}
++
++/*
++ * IPv6-specific closure over IPAddressOrRange_cmp, since sk_sort()
++ * comparision routines are only allowed two arguments.
++ */
++static int v6IPAddressOrRange_cmp(const IPAddressOrRange * const *a,
++ const IPAddressOrRange * const *b)
++{
++ return IPAddressOrRange_cmp(*a, *b, 16);
++}
++
++/*
++ * Calculate whether a range collapses to a prefix.
++ * See last paragraph of RFC 3779 2.2.3.7.
++ */
++static int range_should_be_prefix(const unsigned char *min,
++ const unsigned char *max,
++ const int length)
++{
++ unsigned char mask;
++ int i, j;
++
++ for (i = 0; i < length && min[i] == max[i]; i++)
++ ;
++ for (j = length - 1; j >= 0 && min[j] == 0x00 && max[j] == 0xFF; j--)
++ ;
++ if (i < j)
++ return -1;
++ if (i > j)
++ return i * 8;
++ mask = min[i] ^ max[i];
++ switch (mask) {
++ case 0x01: j = 7; break;
++ case 0x03: j = 6; break;
++ case 0x07: j = 5; break;
++ case 0x0F: j = 4; break;
++ case 0x1F: j = 3; break;
++ case 0x3F: j = 2; break;
++ case 0x7F: j = 1; break;
++ default: return -1;
++ }
++ if ((min[i] & mask) != 0 || (max[i] & mask) != mask)
++ return -1;
++ else
++ return i * 8 + j;
++}
++
++/*
++ * Construct a prefix.
++ */
++static int make_addressPrefix(IPAddressOrRange **result,
++ unsigned char *addr,
++ const int prefixlen)
++{
++ int bytelen = (prefixlen + 7) / 8, bitlen = prefixlen % 8;
++ IPAddressOrRange *aor = IPAddressOrRange_new();
++
++ if (aor == NULL)
++ return 0;
++ aor->type = IPAddressOrRange_addressPrefix;
++ if (aor->u.addressPrefix == NULL &&
++ (aor->u.addressPrefix = ASN1_BIT_STRING_new()) == NULL)
++ goto err;
++ if (!ASN1_BIT_STRING_set(aor->u.addressPrefix, addr, bytelen))
++ goto err;
++ aor->u.addressPrefix->flags &= ~7;
++ aor->u.addressPrefix->flags |= ASN1_STRING_FLAG_BITS_LEFT;
++ if (bitlen > 0) {
++ aor->u.addressPrefix->data[bytelen - 1] &= ~(0xFF >> bitlen);
++ aor->u.addressPrefix->flags |= 8 - bitlen;
++ }
++
++ *result = aor;
++ return 1;
++
++ err:
++ IPAddressOrRange_free(aor);
++ return 0;
++}
++
++/*
++ * Construct a range. If it can be expressed as a prefix,
++ * return a prefix instead. Doing this here simplifies
++ * the rest of the code considerably.
++ */
++static int make_addressRange(IPAddressOrRange **result,
++ unsigned char *min,
++ unsigned char *max,
++ const int length)
++{
++ IPAddressOrRange *aor;
++ int i, prefixlen;
++
++ if ((prefixlen = range_should_be_prefix(min, max, length)) >= 0)
++ return make_addressPrefix(result, min, prefixlen);
++
++ if ((aor = IPAddressOrRange_new()) == NULL)
++ return 0;
++ aor->type = IPAddressOrRange_addressRange;
++ assert(aor->u.addressRange == NULL);
++ if ((aor->u.addressRange = IPAddressRange_new()) == NULL)
++ goto err;
++ if (aor->u.addressRange->min == NULL &&
++ (aor->u.addressRange->min = ASN1_BIT_STRING_new()) == NULL)
++ goto err;
++ if (aor->u.addressRange->max == NULL &&
++ (aor->u.addressRange->max = ASN1_BIT_STRING_new()) == NULL)
++ goto err;
++
++ for (i = length; i > 0 && min[i - 1] == 0x00; --i)
++ ;
++ if (!ASN1_BIT_STRING_set(aor->u.addressRange->min, min, i))
++ goto err;
++ aor->u.addressRange->min->flags &= ~7;
++ aor->u.addressRange->min->flags |= ASN1_STRING_FLAG_BITS_LEFT;
++ if (i > 0) {
++ unsigned char b = min[i - 1];
++ int j = 1;
++ while ((b & (0xFFU >> j)) != 0)
++ ++j;
++ aor->u.addressRange->min->flags |= 8 - j;
++ }
++
++ for (i = length; i > 0 && max[i - 1] == 0xFF; --i)
++ ;
++ if (!ASN1_BIT_STRING_set(aor->u.addressRange->max, max, i))
++ goto err;
++ aor->u.addressRange->max->flags &= ~7;
++ aor->u.addressRange->max->flags |= ASN1_STRING_FLAG_BITS_LEFT;
++ if (i > 0) {
++ unsigned char b = max[i - 1];
++ int j = 1;
++ while ((b & (0xFFU >> j)) != (0xFFU >> j))
++ ++j;
++ aor->u.addressRange->max->flags |= 8 - j;
++ }
++
++ *result = aor;
++ return 1;
++
++ err:
++ IPAddressOrRange_free(aor);
++ return 0;
++}
++
++/*
++ * Construct a new address family or find an existing one.
++ */
++static IPAddressFamily *make_IPAddressFamily(IPAddrBlocks *addr,
++ const unsigned afi,
++ const unsigned *safi)
++{
++ IPAddressFamily *f;
++ unsigned char key[3];
++ unsigned keylen;
++ int i;
++
++ key[0] = (afi >> 8) & 0xFF;
++ key[1] = afi & 0xFF;
++ if (safi != NULL) {
++ key[2] = *safi & 0xFF;
++ keylen = 3;
++ } else {
++ keylen = 2;
++ }
++
++ for (i = 0; i < sk_IPAddressFamily_num(addr); i++) {
++ f = sk_IPAddressFamily_value(addr, i);
++ assert(f->addressFamily->data != NULL);
++ if (f->addressFamily->length == keylen &&
++ !memcmp(f->addressFamily->data, key, keylen))
++ return f;
++ }
++
++ if ((f = IPAddressFamily_new()) == NULL)
++ goto err;
++ if (f->ipAddressChoice == NULL &&
++ (f->ipAddressChoice = IPAddressChoice_new()) == NULL)
++ goto err;
++ if (f->addressFamily == NULL &&
++ (f->addressFamily = ASN1_OCTET_STRING_new()) == NULL)
++ goto err;
++ if (!ASN1_OCTET_STRING_set(f->addressFamily, key, keylen))
++ goto err;
++ if (!sk_IPAddressFamily_push(addr, f))
++ goto err;
++
++ return f;
++
++ err:
++ IPAddressFamily_free(f);
++ return NULL;
++}
++
++/*
++ * Add an inheritance element.
++ */
++static int addr_add_inherit(IPAddrBlocks *addr,
++ const unsigned afi,
++ const unsigned *safi)
++{
++ IPAddressFamily *f = make_IPAddressFamily(addr, afi, safi);
++ if (f == NULL ||
++ f->ipAddressChoice == NULL ||
++ (f->ipAddressChoice->type == IPAddressChoice_addressesOrRanges &&
++ f->ipAddressChoice->u.addressesOrRanges != NULL))
++ return 0;
++ if (f->ipAddressChoice->type == IPAddressChoice_inherit &&
++ f->ipAddressChoice->u.inherit != NULL)
++ return 1;
++ if (f->ipAddressChoice->u.inherit == NULL &&
++ (f->ipAddressChoice->u.inherit = ASN1_NULL_new()) == NULL)
++ return 0;
++ f->ipAddressChoice->type = IPAddressChoice_inherit;
++ return 1;
++}
++
++/*
++ * Construct an IPAddressOrRange sequence, or return an existing one.
++ */
++static IPAddressOrRanges *make_prefix_or_range(IPAddrBlocks *addr,
++ const unsigned afi,
++ const unsigned *safi)
++{
++ IPAddressFamily *f = make_IPAddressFamily(addr, afi, safi);
++ IPAddressOrRanges *aors = NULL;
++
++ if (f == NULL ||
++ f->ipAddressChoice == NULL ||
++ (f->ipAddressChoice->type == IPAddressChoice_inherit &&
++ f->ipAddressChoice->u.inherit != NULL))
++ return NULL;
++ if (f->ipAddressChoice->type == IPAddressChoice_addressesOrRanges)
++ aors = f->ipAddressChoice->u.addressesOrRanges;
++ if (aors != NULL)
++ return aors;
++ if ((aors = sk_IPAddressOrRange_new_null()) == NULL)
++ return NULL;
++ switch (afi) {
++ case IANA_AFI_IPV4:
++ sk_IPAddressOrRange_set_cmp_func(aors, v4IPAddressOrRange_cmp);
++ break;
++ case IANA_AFI_IPV6:
++ sk_IPAddressOrRange_set_cmp_func(aors, v6IPAddressOrRange_cmp);
++ break;
++ }
++ f->ipAddressChoice->type = IPAddressChoice_addressesOrRanges;
++ f->ipAddressChoice->u.addressesOrRanges = aors;
++ return aors;
++}
++
++/*
++ * Add a prefix.
++ */
++static int addr_add_prefix(IPAddrBlocks *addr,
++ const unsigned afi,
++ const unsigned *safi,
++ unsigned char *a,
++ const int prefixlen)
++{
++ IPAddressOrRanges *aors = make_prefix_or_range(addr, afi, safi);
++ IPAddressOrRange *aor;
++ if (aors == NULL || !make_addressPrefix(&aor, a, prefixlen))
++ return 0;
++ if (sk_IPAddressOrRange_push(aors, aor))
++ return 1;
++ IPAddressOrRange_free(aor);
++ return 0;
++}
++
++/*
++ * Add a range.
++ */
++static int addr_add_range(IPAddrBlocks *addr,
++ const unsigned afi,
++ const unsigned *safi,
++ unsigned char *min,
++ unsigned char *max)
++{
++ IPAddressOrRanges *aors = make_prefix_or_range(addr, afi, safi);
++ IPAddressOrRange *aor;
++ int length = length_from_afi(afi);
++ if (aors == NULL)
++ return 0;
++ if (!make_addressRange(&aor, min, max, length))
++ return 0;
++ if (sk_IPAddressOrRange_push(aors, aor))
++ return 1;
++ IPAddressOrRange_free(aor);
++ return 0;
++}
++
++/*
++ * Extract min and max values from an IPAddressOrRange.
++ */
++static void extract_min_max(IPAddressOrRange *aor,
++ unsigned char *min,
++ unsigned char *max,
++ int length)
++{
++ assert(aor != NULL && min != NULL && max != NULL);
++ switch (aor->type) {
++ case IPAddressOrRange_addressPrefix:
++ addr_expand(min, aor->u.addressPrefix, length, 0x00);
++ addr_expand(max, aor->u.addressPrefix, length, 0xFF);
++ return;
++ case IPAddressOrRange_addressRange:
++ addr_expand(min, aor->u.addressRange->min, length, 0x00);
++ addr_expand(max, aor->u.addressRange->max, length, 0xFF);
++ return;
++ }
++}
++
++/*
++ * Sort comparision function for a sequence of IPAddressFamily.
++ *
++ * The last paragraph of RFC 3779 2.2.3.3 is slightly ambiguous about
++ * the ordering: I can read it as meaning that IPv6 without a SAFI
++ * comes before IPv4 with a SAFI, which seems pretty weird. The
++ * examples in appendix B suggest that the author intended the
++ * null-SAFI rule to apply only within a single AFI, which is what I
++ * would have expected and is what the following code implements.
++ */
++static int IPAddressFamily_cmp(const IPAddressFamily * const *a_,
++ const IPAddressFamily * const *b_)
++{
++ const ASN1_OCTET_STRING *a = (*a_)->addressFamily;
++ const ASN1_OCTET_STRING *b = (*b_)->addressFamily;
++ int len = (( a->length <= b->length) ? a->length : b->length);
++ int cmp = memcmp(a->data, b->data, len);
++ return cmp ? cmp : a->length - b->length;
++}
++
++/*
++ * Check whether an IPAddrBLocks is in canonical form.
++ */
++int v3_addr_is_canonical(IPAddrBlocks *addr)
++{
++ unsigned char a_min[ADDR_RAW_BUF_LEN], a_max[ADDR_RAW_BUF_LEN];
++ unsigned char b_min[ADDR_RAW_BUF_LEN], b_max[ADDR_RAW_BUF_LEN];
++ IPAddressOrRanges *aors;
++ int i, j, k;
++
++ /*
++ * Empty extension is cannonical.
++ */
++ if (addr == NULL)
++ return 1;
++
++ /*
++ * Check whether the top-level list is in order.
++ */
++ for (i = 0; i < sk_IPAddressFamily_num(addr) - 1; i++) {
++ const IPAddressFamily *a = sk_IPAddressFamily_value(addr, i);
++ const IPAddressFamily *b = sk_IPAddressFamily_value(addr, i + 1);
++ if (IPAddressFamily_cmp(&a, &b) >= 0)
++ return 0;
++ }
++
++ /*
++ * Top level's ok, now check each address family.
++ */
++ for (i = 0; i < sk_IPAddressFamily_num(addr); i++) {
++ IPAddressFamily *f = sk_IPAddressFamily_value(addr, i);
++ int length = length_from_afi(afi_from_addressfamily(f));
++
++ /*
++ * Inheritance is canonical. Anything other than inheritance or
++ * a SEQUENCE OF IPAddressOrRange is an ASN.1 error or something.
++ */
++ if (f == NULL || f->ipAddressChoice == NULL)
++ return 0;
++ switch (f->ipAddressChoice->type) {
++ case IPAddressChoice_inherit:
++ continue;
++ case IPAddressChoice_addressesOrRanges:
++ break;
++ default:
++ return 0;
++ }
++
++ /*
++ * It's an IPAddressOrRanges sequence, check it.
++ */
++ aors = f->ipAddressChoice->u.addressesOrRanges;
++ if (sk_IPAddressOrRange_num(aors) == 0)
++ return 0;
++ for (j = 0; j < sk_IPAddressOrRange_num(aors) - 1; j++) {
++ IPAddressOrRange *a = sk_IPAddressOrRange_value(aors, j);
++ IPAddressOrRange *b = sk_IPAddressOrRange_value(aors, j + 1);
++
++ extract_min_max(a, a_min, a_max, length);
++ extract_min_max(b, b_min, b_max, length);
++
++ /*
++ * Punt misordered list, overlapping start, or inverted range.
++ */
++ if (memcmp(a_min, b_min, length) >= 0 ||
++ memcmp(a_min, a_max, length) > 0 ||
++ memcmp(b_min, b_max, length) > 0)
++ return 0;
++
++ /*
++ * Punt if adjacent or overlapping. Check for adjacency by
++ * subtracting one from b_min first.
++ */
++ for (k = length - 1; k >= 0 && b_min[k]-- == 0x00; k--)
++ ;
++ if (memcmp(a_max, b_min, length) >= 0)
++ return 0;
++
++ /*
++ * Check for range that should be expressed as a prefix.
++ */
++ if (a->type == IPAddressOrRange_addressRange &&
++ range_should_be_prefix(a_min, a_max, length) >= 0)
++ return 0;
++ }
++
++ /*
++ * Check final range to see if it should be a prefix.
++ */
++ j = sk_IPAddressOrRange_num(aors) - 1;
++ {
++ IPAddressOrRange *a = sk_IPAddressOrRange_value(aors, j);
++ if (a->type == IPAddressOrRange_addressRange) {
++ extract_min_max(a, a_min, a_max, length);
++ if (range_should_be_prefix(a_min, a_max, length) >= 0)
++ return 0;
++ }
++ }
++ }
++
++ /*
++ * If we made it through all that, we're happy.
++ */
++ return 1;
++}
++
++/*
++ * Whack an IPAddressOrRanges into canonical form.
++ */
++static int IPAddressOrRanges_canonize(IPAddressOrRanges *aors,
++ const unsigned afi)
++{
++ int i, j, length = length_from_afi(afi);
++
++ /*
++ * Sort the IPAddressOrRanges sequence.
++ */
++ sk_IPAddressOrRange_sort(aors);
++
++ /*
++ * Clean up representation issues, punt on duplicates or overlaps.
++ */
++ for (i = 0; i < sk_IPAddressOrRange_num(aors) - 1; i++) {
++ IPAddressOrRange *a = sk_IPAddressOrRange_value(aors, i);
++ IPAddressOrRange *b = sk_IPAddressOrRange_value(aors, i + 1);
++ unsigned char a_min[ADDR_RAW_BUF_LEN], a_max[ADDR_RAW_BUF_LEN];
++ unsigned char b_min[ADDR_RAW_BUF_LEN], b_max[ADDR_RAW_BUF_LEN];
++
++ extract_min_max(a, a_min, a_max, length);
++ extract_min_max(b, b_min, b_max, length);
++
++ /*
++ * Punt overlaps.
++ */
++ if (memcmp(a_max, b_min, length) >= 0)
++ return 0;
++
++ /*
++ * Merge if a and b are adjacent. We check for
++ * adjacency by subtracting one from b_min first.
++ */
++ for (j = length - 1; j >= 0 && b_min[j]-- == 0x00; j--)
++ ;
++ if (memcmp(a_max, b_min, length) == 0) {
++ IPAddressOrRange *merged;
++ if (!make_addressRange(&merged, a_min, b_max, length))
++ return 0;
++ sk_IPAddressOrRange_set(aors, i, merged);
++ sk_IPAddressOrRange_delete(aors, i + 1);
++ IPAddressOrRange_free(a);
++ IPAddressOrRange_free(b);
++ --i;
++ continue;
++ }
++ }
++
++ return 1;
++}
++
++/*
++ * Whack an IPAddrBlocks extension into canonical form.
++ */
++int v3_addr_canonize(IPAddrBlocks *addr)
++{
++ int i;
++ for (i = 0; i < sk_IPAddressFamily_num(addr); i++) {
++ IPAddressFamily *f = sk_IPAddressFamily_value(addr, i);
++ if (f->ipAddressChoice->type == IPAddressChoice_addressesOrRanges &&
++ !IPAddressOrRanges_canonize(f->ipAddressChoice->u.addressesOrRanges,
++ afi_from_addressfamily(f)))
++ return 0;
++ }
++ sk_IPAddressFamily_sort(addr);
++ assert(v3_addr_is_canonical(addr));
++ return 1;
++}
++
++/*
++ * v2i handler for the IPAddrBlocks extension.
++ */
++static void *v2i_IPAddrBlocks(struct v3_ext_method *method,
++ struct v3_ext_ctx *ctx,
++ STACK_OF(CONF_VALUE) *values)
++{
++ static const char v4addr_chars[] = "0123456789.";
++ static const char v6addr_chars[] = "0123456789.:abcdefABCDEF";
++ IPAddrBlocks *addr = NULL;
++ char *s = NULL, *t;
++ int i;
++
++ if ((addr = sk_IPAddressFamily_new(IPAddressFamily_cmp)) == NULL) {
++ X509V3err(X509V3_F_V2I_IPADDRBLOCKS, ERR_R_MALLOC_FAILURE);
++ return NULL;
++ }
++
++ for (i = 0; i < sk_CONF_VALUE_num(values); i++) {
++ CONF_VALUE *val = sk_CONF_VALUE_value(values, i);
++ unsigned char min[ADDR_RAW_BUF_LEN], max[ADDR_RAW_BUF_LEN];
++ unsigned afi, *safi = NULL, safi_;
++ const char *addr_chars;
++ int prefixlen, i1, i2, delim, length;
++
++ if ( !name_cmp(val->name, "IPv4")) {
++ afi = IANA_AFI_IPV4;
++ } else if (!name_cmp(val->name, "IPv6")) {
++ afi = IANA_AFI_IPV6;
++ } else if (!name_cmp(val->name, "IPv4-SAFI")) {
++ afi = IANA_AFI_IPV4;
++ safi = &safi_;
++ } else if (!name_cmp(val->name, "IPv6-SAFI")) {
++ afi = IANA_AFI_IPV6;
++ safi = &safi_;
++ } else {
++ X509V3err(X509V3_F_V2I_IPADDRBLOCKS, X509V3_R_EXTENSION_NAME_ERROR);
++ X509V3_conf_err(val);
++ goto err;
++ }
++
++ switch (afi) {
++ case IANA_AFI_IPV4:
++ addr_chars = v4addr_chars;
++ break;
++ case IANA_AFI_IPV6:
++ addr_chars = v6addr_chars;
++ break;
++ }
++
++ length = length_from_afi(afi);
++
++ /*
++ * Handle SAFI, if any, and strdup() so we can null-terminate
++ * the other input values.
++ */
++ if (safi != NULL) {
++ *safi = strtoul(val->value, &t, 0);
++ t += strspn(t, " \t");
++ if (*safi > 0xFF || *t++ != ':') {
++ X509V3err(X509V3_F_V2I_IPADDRBLOCKS, X509V3_R_INVALID_SAFI);
++ X509V3_conf_err(val);
++ goto err;
++ }
++ t += strspn(t, " \t");
++ s = strdup(t);
++ } else {
++ s = strdup(val->value);
++ }
++ if (s == NULL) {
++ X509V3err(X509V3_F_V2I_IPADDRBLOCKS, ERR_R_MALLOC_FAILURE);
++ goto err;
++ }
++
++ /*
++ * Check for inheritance. Not worth additional complexity to
++ * optimize this (seldom-used) case.
++ */
++ if (!strcmp(s, "inherit")) {
++ if (!addr_add_inherit(addr, afi, safi)) {
++ X509V3err(X509V3_F_V2I_IPADDRBLOCKS, X509V3_R_INVALID_INHERITANCE);
++ X509V3_conf_err(val);
++ goto err;
++ }
++ OPENSSL_free(s);
++ s = NULL;
++ continue;
++ }
++
++ i1 = strspn(s, addr_chars);
++ i2 = i1 + strspn(s + i1, " \t");
++ delim = s[i2++];
++ s[i1] = '\0';
++
++ if (a2i_ipadd(min, s) != length) {
++ X509V3err(X509V3_F_V2I_IPADDRBLOCKS, X509V3_R_INVALID_IPADDRESS);
++ X509V3_conf_err(val);
++ goto err;
++ }
++
++ switch (delim) {
++ case '/':
++ prefixlen = (int) strtoul(s + i2, &t, 10);
++ if (t == s + i2 || *t != '\0') {
++ X509V3err(X509V3_F_V2I_IPADDRBLOCKS, X509V3_R_EXTENSION_VALUE_ERROR);
++ X509V3_conf_err(val);
++ goto err;
++ }
++ if (!addr_add_prefix(addr, afi, safi, min, prefixlen)) {
++ X509V3err(X509V3_F_V2I_IPADDRBLOCKS, ERR_R_MALLOC_FAILURE);
++ goto err;
++ }
++ break;
++ case '-':
++ i1 = i2 + strspn(s + i2, " \t");
++ i2 = i1 + strspn(s + i1, addr_chars);
++ if (i1 == i2 || s[i2] != '\0') {
++ X509V3err(X509V3_F_V2I_IPADDRBLOCKS, X509V3_R_EXTENSION_VALUE_ERROR);
++ X509V3_conf_err(val);
++ goto err;
++ }
++ if (a2i_ipadd(max, s + i1) != length) {
++ X509V3err(X509V3_F_V2I_IPADDRBLOCKS, X509V3_R_INVALID_IPADDRESS);
++ X509V3_conf_err(val);
++ goto err;
++ }
++ if (!addr_add_range(addr, afi, safi, min, max)) {
++ X509V3err(X509V3_F_V2I_IPADDRBLOCKS, ERR_R_MALLOC_FAILURE);
++ goto err;
++ }
++ break;
++ case '\0':
++ if (!addr_add_prefix(addr, afi, safi, min, length * 8)) {
++ X509V3err(X509V3_F_V2I_IPADDRBLOCKS, ERR_R_MALLOC_FAILURE);
++ goto err;
++ }
++ break;
++ default:
++ X509V3err(X509V3_F_V2I_IPADDRBLOCKS, X509V3_R_EXTENSION_VALUE_ERROR);
++ X509V3_conf_err(val);
++ goto err;
++ }
++
++ OPENSSL_free(s);
++ s = NULL;
++ }
++
++ /*
++ * Canonize the result, then we're done.
++ */
++ if (!v3_addr_canonize(addr))
++ goto err;
++ return addr;
++
++ err:
++ OPENSSL_free(s);
++ sk_IPAddressFamily_pop_free(addr, IPAddressFamily_free);
++ return NULL;
++}
++
++/*
++ * OpenSSL dispatch
++ */
++X509V3_EXT_METHOD v3_addr = {
++ NID_sbgp_ipAddrBlock, /* nid */
++ 0, /* flags */
++ ASN1_ITEM_ref(IPAddrBlocks), /* template */
++ 0, 0, 0, 0, /* old functions, ignored */
++ 0, /* i2s */
++ 0, /* s2i */
++ 0, /* i2v */
++ v2i_IPAddrBlocks, /* v2i */
++ i2r_IPAddrBlocks, /* i2r */
++ 0, /* r2i */
++ NULL /* extension-specific data */
++};
++
++/*
++ * Figure out whether extension sues inheritance.
++ */
++int v3_addr_inherits(IPAddrBlocks *addr)
++{
++ int i;
++ if (addr == NULL)
++ return 0;
++ for (i = 0; i < sk_IPAddressFamily_num(addr); i++) {
++ IPAddressFamily *f = sk_IPAddressFamily_value(addr, i);
++ if (f->ipAddressChoice->type == IPAddressChoice_inherit)
++ return 1;
++ }
++ return 0;
++}
++
++/*
++ * Figure out whether parent contains child.
++ */
++static int addr_contains(IPAddressOrRanges *parent,
++ IPAddressOrRanges *child,
++ int length)
++{
++ unsigned char p_min[ADDR_RAW_BUF_LEN], p_max[ADDR_RAW_BUF_LEN];
++ unsigned char c_min[ADDR_RAW_BUF_LEN], c_max[ADDR_RAW_BUF_LEN];
++ int p, c;
++
++ if (child == NULL || parent == child)
++ return 1;
++ if (parent == NULL)
++ return 0;
++
++ p = 0;
++ for (c = 0; c < sk_IPAddressOrRange_num(child); c++) {
++ extract_min_max(sk_IPAddressOrRange_value(child, c),
++ c_min, c_max, length);
++ for (;; p++) {
++ if (p >= sk_IPAddressOrRange_num(parent))
++ return 0;
++ extract_min_max(sk_IPAddressOrRange_value(parent, p),
++ p_min, p_max, length);
++ if (memcmp(p_max, c_max, length) < 0)
++ continue;
++ if (memcmp(p_min, c_min, length) > 0)
++ return 0;
++ break;
++ }
++ }
++
++ return 1;
++}
++
++/*
++ * Test whether a is a subset of b.
++ */
++int v3_addr_subset(IPAddrBlocks *a, IPAddrBlocks *b)
++{
++ int i;
++ if (a == NULL || a == b)
++ return 1;
++ if (b == NULL || v3_addr_inherits(a) || v3_addr_inherits(b))
++ return 0;
++ sk_IPAddressFamily_set_cmp_func(b, IPAddressFamily_cmp);
++ for (i = 0; i < sk_IPAddressFamily_num(a); i++) {
++ IPAddressFamily *fa = sk_IPAddressFamily_value(a, i);
++ int j = sk_IPAddressFamily_find(b, fa);
++ IPAddressFamily *fb = sk_IPAddressFamily_value(b, j);
++ if (!addr_contains(fb->ipAddressChoice->u.addressesOrRanges,
++ fa->ipAddressChoice->u.addressesOrRanges,
++ length_from_afi(afi_from_addressfamily(fb))))
++ return 0;
++ }
++ return 1;
++}
++
++/*
++ * Validation error handling via callback.
++ */
++#define validation_err(_err_) \
++ do { \
++ if (ctx != NULL) { \
++ ctx->error = _err_; \
++ ctx->error_depth = i; \
++ ctx->current_cert = x; \
++ ret = ctx->verify_cb(0, ctx); \
++ } else { \
++ ret = 0; \
++ } \
++ if (!ret) \
++ goto done; \
++ } while (0)
++
++/*
++ * Core code for RFC 3779 2.3 path validation.
++ */
++static int v3_addr_validate_path_internal(X509_STORE_CTX *ctx,
++ STACK_OF(X509) *chain,
++ IPAddrBlocks *ext)
++{
++ IPAddrBlocks *child = NULL;
++ int i, j, ret = 1;
++ X509 *x;
++
++ assert(chain != NULL && sk_X509_num(chain) > 0);
++ assert(ctx != NULL || ext != NULL);
++ assert(ctx == NULL || ctx->verify_cb != NULL);
++
++ /*
++ * Figure out where to start. If we don't have an extension to
++ * check, we're done. Otherwise, check canonical form and
++ * set up for walking up the chain.
++ */
++ if (ext != NULL) {
++ i = -1;
++ } else {
++ i = 0;
++ x = sk_X509_value(chain, i);
++ assert(x != NULL);
++ if ((ext = x->rfc3779_addr) == NULL)
++ goto done;
++ }
++ if (!v3_addr_is_canonical(ext))
++ validation_err(X509_V_ERR_INVALID_EXTENSION);
++ sk_IPAddressFamily_set_cmp_func(ext, IPAddressFamily_cmp);
++ if ((child = sk_IPAddressFamily_dup(ext)) == NULL) {
++ X509V3err(X509V3_F_V3_ADDR_VALIDATE_PATH_INTERNAL, ERR_R_MALLOC_FAILURE);
++ ret = 0;
++ goto done;
++ }
++
++ /*
++ * Now walk up the chain. No cert may list resources that its
++ * parent doesn't list.
++ */
++ for (i++; i < sk_X509_num(chain); i++) {
++ x = sk_X509_value(chain, i);
++ assert(x != NULL);
++ if (!v3_addr_is_canonical(x->rfc3779_addr))
++ validation_err(X509_V_ERR_INVALID_EXTENSION);
++ if (x->rfc3779_addr == NULL) {
++ for (j = 0; j < sk_IPAddressFamily_num(child); j++) {
++ IPAddressFamily *fc = sk_IPAddressFamily_value(child, j);
++ if (fc->ipAddressChoice->type != IPAddressChoice_inherit) {
++ validation_err(X509_V_ERR_UNNESTED_RESOURCE);
++ break;
++ }
++ }
++ continue;
++ }
++ sk_IPAddressFamily_set_cmp_func(x->rfc3779_addr, IPAddressFamily_cmp);
++ for (j = 0; j < sk_IPAddressFamily_num(child); j++) {
++ IPAddressFamily *fc = sk_IPAddressFamily_value(child, j);
++ int k = sk_IPAddressFamily_find(x->rfc3779_addr, fc);
++ IPAddressFamily *fp = sk_IPAddressFamily_value(x->rfc3779_addr, k);
++ if (fp == NULL) {
++ if (fc->ipAddressChoice->type == IPAddressChoice_addressesOrRanges) {
++ validation_err(X509_V_ERR_UNNESTED_RESOURCE);
++ break;
++ }
++ continue;
++ }
++ if (fp->ipAddressChoice->type == IPAddressChoice_addressesOrRanges) {
++ if (fc->ipAddressChoice->type == IPAddressChoice_inherit ||
++ addr_contains(fp->ipAddressChoice->u.addressesOrRanges,
++ fc->ipAddressChoice->u.addressesOrRanges,
++ length_from_afi(afi_from_addressfamily(fc))))
++ sk_IPAddressFamily_set(child, j, fp);
++ else
++ validation_err(X509_V_ERR_UNNESTED_RESOURCE);
++ }
++ }
++ }
++
++ /*
++ * Trust anchor can't inherit.
++ */
++ if (x->rfc3779_addr != NULL) {
++ for (j = 0; j < sk_IPAddressFamily_num(x->rfc3779_addr); j++) {
++ IPAddressFamily *fp = sk_IPAddressFamily_value(x->rfc3779_addr, j);
++ if (fp->ipAddressChoice->type == IPAddressChoice_inherit &&
++ sk_IPAddressFamily_find(child, fp) >= 0)
++ validation_err(X509_V_ERR_UNNESTED_RESOURCE);
++ }
++ }
++
++ done:
++ sk_IPAddressFamily_free(child);
++ return ret;
++}
++
++#undef validation_err
++
++/*
++ * RFC 3779 2.3 path validation -- called from X509_verify_cert().
++ */
++int v3_addr_validate_path(X509_STORE_CTX *ctx)
++{
++ return v3_addr_validate_path_internal(ctx, ctx->chain, NULL);
++}
++
++/*
++ * RFC 3779 2.3 path validation of an extension.
++ * Test whether chain covers extension.
++ */
++int v3_addr_validate_resource_set(STACK_OF(X509) *chain,
++ IPAddrBlocks *ext,
++ int allow_inheritance)
++{
++ if (ext == NULL)
++ return 1;
++ if (chain == NULL || sk_X509_num(chain) == 0)
++ return 0;
++ if (!allow_inheritance && v3_addr_inherits(ext))
++ return 0;
++ return v3_addr_validate_path_internal(NULL, chain, ext);
++}
+
+Index: crypto/x509v3/ext_dat.h
+===================================================================
+--- crypto/x509v3/ext_dat.h (.../vendor/0.9.8b) (revision 251)
++++ crypto/x509v3/ext_dat.h (.../trunk) (revision 251)
+@@ -67,6 +67,7 @@
+ extern X509V3_EXT_METHOD v3_crl_hold, v3_pci;
+ extern X509V3_EXT_METHOD v3_policy_mappings, v3_policy_constraints;
+ extern X509V3_EXT_METHOD v3_name_constraints, v3_inhibit_anyp;
++extern X509V3_EXT_METHOD v3_addr, v3_asid;
+
+ /* This table will be searched using OBJ_bsearch so it *must* kept in
+ * order of the ext_nid values.
+@@ -99,6 +100,8 @@
+ #endif
+ &v3_sxnet,
+ &v3_info,
++&v3_addr,
++&v3_asid,
+ #ifndef OPENSSL_NO_OCSP
+ &v3_ocsp_nonce,
+ &v3_ocsp_crlid,
+
+Index: crypto/asn1/x_x509.c
+===================================================================
+--- crypto/asn1/x_x509.c (.../vendor/0.9.8b) (revision 251)
++++ crypto/asn1/x_x509.c (.../trunk) (revision 251)
+@@ -94,6 +94,8 @@
+ ret->ex_pathlen = -1;
+ ret->skid = NULL;
+ ret->akid = NULL;
++ ret->rfc3779_addr = NULL;
++ ret->rfc3779_asid = NULL;
+ ret->aux = NULL;
+ CRYPTO_new_ex_data(CRYPTO_EX_INDEX_X509, ret, &ret->ex_data);
+ break;
+@@ -109,6 +111,8 @@
+ ASN1_OCTET_STRING_free(ret->skid);
+ AUTHORITY_KEYID_free(ret->akid);
+ policy_cache_free(ret->policy_cache);
++ sk_IPAddressFamily_pop_free(ret->rfc3779_addr, IPAddressFamily_free);
++ ASIdentifiers_free(ret->rfc3779_asid);
+
+ if (ret->name != NULL) OPENSSL_free(ret->name);
+ break;
+
+Index: crypto/x509/x509_vfy.h
+===================================================================
+--- crypto/x509/x509_vfy.h (.../vendor/0.9.8b) (revision 251)
++++ crypto/x509/x509_vfy.h (.../trunk) (revision 251)
+@@ -331,6 +331,7 @@
+ #define X509_V_ERR_INVALID_POLICY_EXTENSION 42
+ #define X509_V_ERR_NO_EXPLICIT_POLICY 43
+
++#define X509_V_ERR_UNNESTED_RESOURCE 44
+
+ /* The application is not happy */
+ #define X509_V_ERR_APPLICATION_VERIFICATION 50
+Index: crypto/x509/x509_txt.c
+===================================================================
+--- crypto/x509/x509_txt.c (.../vendor/0.9.8b) (revision 251)
++++ crypto/x509/x509_txt.c (.../trunk) (revision 251)
+@@ -162,6 +162,8 @@
+ return("invalid or inconsistent certificate policy extension");
+ case X509_V_ERR_NO_EXPLICIT_POLICY:
+ return("no explicit policy");
++ case X509_V_ERR_UNNESTED_RESOURCE:
++ return("RFC 3779 resource not subset of parent's resources");
+ default:
+ BIO_snprintf(buf,sizeof buf,"error number %ld",n);
+ return(buf);
+Index: crypto/x509/x509.h
+===================================================================
+--- crypto/x509/x509.h (.../vendor/0.9.8b) (revision 251)
++++ crypto/x509/x509.h (.../trunk) (revision 251)
+@@ -288,6 +288,8 @@
+ ASN1_OCTET_STRING *skid;
+ struct AUTHORITY_KEYID_st *akid;
+ X509_POLICY_CACHE *policy_cache;
++ STACK_OF(IPAddressFamily) *rfc3779_addr;
++ struct ASIdentifiers_st *rfc3779_asid;
+ #ifndef OPENSSL_NO_SHA
+ unsigned char sha1_hash[SHA_DIGEST_LENGTH];
+ #endif
+Index: crypto/x509/x509_vfy.c
+===================================================================
+--- crypto/x509/x509_vfy.c (.../vendor/0.9.8b) (revision 251)
++++ crypto/x509/x509_vfy.c (.../trunk) (revision 251)
+@@ -312,6 +312,12 @@
+ ok=internal_verify(ctx);
+ if(!ok) goto end;
+
++ /* RFC 3779 path validation, now that CRL check has been done */
++ ok = v3_asid_validate_path(ctx);
++ if (!ok) goto end;
++ ok = v3_addr_validate_path(ctx);
++ if (!ok) goto end;
++
+ /* If we get this far evaluate policies */
+ if (!bad_chain && (ctx->param->flags & X509_V_FLAG_POLICY_CHECK))
+ ok = ctx->check_policy(ctx);
+
+Index: util/libeay.num
+===================================================================
+--- util/libeay.num (.../vendor/0.9.8b) (revision 251)
++++ util/libeay.num (.../trunk) (revision 251)
+@@ -3380,3 +3380,64 @@
+ X509_VERIFY_PARAM_get_flags 3781 EXIST::FUNCTION:
+ EVP_CIPHER_CTX_new 3782 EXIST::FUNCTION:
+ EVP_CIPHER_CTX_free 3783 EXIST::FUNCTION:
++ASIdentifiers_free 3784 EXIST::FUNCTION:
++i2d_ASIdOrRange 3785 EXIST::FUNCTION:
++IPAddressChoice_free 3786 EXIST::FUNCTION:
++IPAddressOrRange_it 3787 EXIST:!EXPORT_VAR_AS_FUNCTION:VARIABLE:
++IPAddressOrRange_it 3787 EXIST:EXPORT_VAR_AS_FUNCTION:FUNCTION:
++ASIdentifiers_it 3788 EXIST:!EXPORT_VAR_AS_FUNCTION:VARIABLE:
++ASIdentifiers_it 3788 EXIST:EXPORT_VAR_AS_FUNCTION:FUNCTION:
++IPAddressChoice_it 3789 EXIST:!EXPORT_VAR_AS_FUNCTION:VARIABLE:
++IPAddressChoice_it 3789 EXIST:EXPORT_VAR_AS_FUNCTION:FUNCTION:
++d2i_ASRange 3790 EXIST::FUNCTION:
++IPAddressRange_free 3791 EXIST::FUNCTION:
++IPAddressRange_new 3792 EXIST::FUNCTION:
++ASIdOrRange_new 3793 EXIST::FUNCTION:
++i2d_ASRange 3794 EXIST::FUNCTION:
++IPAddressRange_it 3795 EXIST:!EXPORT_VAR_AS_FUNCTION:VARIABLE:
++IPAddressRange_it 3795 EXIST:EXPORT_VAR_AS_FUNCTION:FUNCTION:
++IPAddressChoice_new 3796 EXIST::FUNCTION:
++ASIdentifierChoice_new 3797 EXIST::FUNCTION:
++ASRange_free 3798 EXIST::FUNCTION:
++IPAddressFamily_free 3799 EXIST::FUNCTION:
++i2d_IPAddressFamily 3800 EXIST::FUNCTION:
++IPAddressOrRange_new 3801 EXIST::FUNCTION:
++d2i_IPAddressRange 3802 EXIST::FUNCTION:
++IPAddressOrRange_free 3803 EXIST::FUNCTION:
++d2i_IPAddressFamily 3804 EXIST::FUNCTION:
++i2d_ASIdentifierChoice 3805 EXIST::FUNCTION:
++ASRange_it 3806 EXIST:!EXPORT_VAR_AS_FUNCTION:VARIABLE:
++ASRange_it 3806 EXIST:EXPORT_VAR_AS_FUNCTION:FUNCTION:
++d2i_ASIdentifiers 3807 EXIST::FUNCTION:
++ASRange_new 3808 EXIST::FUNCTION:
++d2i_IPAddressChoice 3809 EXIST::FUNCTION:
++i2d_IPAddressOrRange 3810 EXIST::FUNCTION:
++ASIdOrRange_it 3811 EXIST:!EXPORT_VAR_AS_FUNCTION:VARIABLE:
++ASIdOrRange_it 3811 EXIST:EXPORT_VAR_AS_FUNCTION:FUNCTION:
++i2d_IPAddressChoice 3812 EXIST::FUNCTION:
++ASIdentifiers_new 3813 EXIST::FUNCTION:
++IPAddressFamily_new 3814 EXIST::FUNCTION:
++i2d_IPAddressRange 3815 EXIST::FUNCTION:
++IPAddressFamily_it 3816 EXIST:!EXPORT_VAR_AS_FUNCTION:VARIABLE:
++IPAddressFamily_it 3816 EXIST:EXPORT_VAR_AS_FUNCTION:FUNCTION:
++d2i_IPAddressOrRange 3817 EXIST::FUNCTION:
++ASIdentifierChoice_it 3818 EXIST:!EXPORT_VAR_AS_FUNCTION:VARIABLE:
++ASIdentifierChoice_it 3818 EXIST:EXPORT_VAR_AS_FUNCTION:FUNCTION:
++d2i_ASIdentifierChoice 3819 EXIST::FUNCTION:
++ASIdOrRange_free 3820 EXIST::FUNCTION:
++ASIdentifierChoice_free 3821 EXIST::FUNCTION:
++d2i_ASIdOrRange 3822 EXIST::FUNCTION:
++i2d_ASIdentifiers 3823 EXIST::FUNCTION:
++v3_addr_validate_path 3824 EXIST::FUNCTION:
++v3_asid_validate_path 3825 EXIST::FUNCTION:
++a2i_ipadd 3826 EXIST::FUNCTION:
++v3_asid_is_canonical 3827 EXIST::FUNCTION:
++v3_addr_validate_resource_set 3828 EXIST::FUNCTION:
++v3_asid_canonize 3829 EXIST::FUNCTION:
++v3_asid_validate_resource_set 3830 EXIST::FUNCTION:
++v3_addr_is_canonical 3831 EXIST::FUNCTION:
++v3_addr_canonize 3832 EXIST::FUNCTION:
++v3_addr_inherits 3833 EXIST::FUNCTION:
++v3_addr_subset 3834 EXIST::FUNCTION:
++v3_asid_subset 3835 EXIST::FUNCTION:
++v3_asid_inherits 3836 EXIST::FUNCTION:
+