Finish off support for Certificate Policies extension.
diff --git a/CHANGES b/CHANGES
index a18f428..4e58f2d 100644
--- a/CHANGES
+++ b/CHANGES
@@ -14,9 +14,8 @@
   *) SPARC v8 assembler BIGNUM implementation.
      [Andy Polyakov <appro@fy.chalmers.se>]
 
-  *) Initial support for Certificate Policies extension: print works but
-     setting doesn't work fully (yet). Also various additions to support
-     the r2i method this extension will use.
+  *) Support for Certificate Policies extension: both print and set.
+     Various additions to support the r2i method this extension will use.
      [Steve Henson]
 
   *) A lot of constification, and fix a bug in X509_NAME_oneline() that could
diff --git a/crypto/x509v3/v3_cpols.c b/crypto/x509v3/v3_cpols.c
index c934004..cb6d0b0 100644
--- a/crypto/x509v3/v3_cpols.c
+++ b/crypto/x509v3/v3_cpols.c
@@ -70,6 +70,8 @@
 static void print_qualifiers(BIO *out, STACK_OF(POLICYQUALINFO) *quals, int indent);
 static void print_notice(BIO *out, USERNOTICE *notice, int indent);
 static POLICYINFO *policy_section(X509V3_CTX *ctx, STACK *polstrs);
+static POLICYQUALINFO *notice_section(X509V3_CTX *ctx, STACK *unot);
+static STACK *nref_nos(STACK *nos);
 
 X509V3_EXT_METHOD v3_cpols = {
 NID_certificate_policies, 0,
@@ -154,9 +156,168 @@
 {
 	int i;
 	CONF_VALUE *cnf;
+	POLICYINFO *pol;
+	POLICYQUALINFO *qual;
+	if(!(pol = POLICYINFO_new())) goto merr;
 	for(i = 0; i < sk_num(polstrs); i++) {
 		cnf = (CONF_VALUE *)sk_value(polstrs, i);
+		if(!strcmp(cnf->name, "policyIdentifier")) {
+			ASN1_OBJECT *pobj;
+			if(!(pobj = OBJ_txt2obj(cnf->value, 0))) {
+				X509V3err(X509V3_F_POLICY_SECTION,X509V3_R_INVALID_OBJECT_IDENTIFIER);
+				X509V3_conf_err(cnf);
+				goto err;
+			}
+			pol->policyid = pobj;
+
+		} else if(!name_cmp(cnf->name, "CPS")) {
+			if(!pol->qualifiers) pol->qualifiers =
+						 sk_POLICYQUALINFO_new_null();
+			if(!(qual = POLICYQUALINFO_new())) goto merr;
+			if(!sk_POLICYQUALINFO_push(pol->qualifiers, qual))
+								 goto merr;
+			qual->pqualid = OBJ_nid2obj(NID_id_qt_cps);
+			qual->d.cpsuri = ASN1_IA5STRING_new();
+			if(!ASN1_STRING_set(qual->d.cpsuri, cnf->value,
+						 strlen(cnf->value))) goto merr;
+		} else if(!name_cmp(cnf->name, "userNotice")) {
+			STACK *unot;
+			if(*cnf->value != '@') {
+				X509V3err(X509V3_F_POLICY_SECTION,X509V3_R_EXPECTED_A_SECTION_NAME);
+				X509V3_conf_err(cnf);
+				goto err;
+			}
+			unot = X509V3_get_section(ctx, cnf->value + 1);
+			if(!unot) {
+				X509V3err(X509V3_F_POLICY_SECTION,X509V3_R_INVALID_SECTION);
+
+				X509V3_conf_err(cnf);
+				goto err;
+			}
+			qual = notice_section(ctx, unot);
+			X509V3_section_free(ctx, unot);
+			if(!qual) goto err;
+			if(!sk_POLICYQUALINFO_push(pol->qualifiers, qual))
+								 goto merr;
+		} else {
+			X509V3err(X509V3_F_POLICY_SECTION,X509V3_R_INVALID_OPTION);
+
+			X509V3_conf_err(cnf);
+			goto err;
+		}
 	}
+	if(!pol->policyid) {
+		X509V3err(X509V3_F_POLICY_SECTION,X509V3_R_NO_POLICY_IDENTIFIER);
+		goto err;
+	}
+
+	return pol;
+
+	err:
+	POLICYINFO_free(pol);
+	return NULL;
+	
+	merr:
+	X509V3err(X509V3_F_POLICY_SECTION,ERR_R_MALLOC_FAILURE);
+	POLICYINFO_free(pol);
+	return NULL;
+	
+}
+
+static POLICYQUALINFO *notice_section(ctx, unot)
+X509V3_CTX *ctx;
+STACK *unot;
+{
+	int i;
+	CONF_VALUE *cnf;
+	USERNOTICE *not;
+	POLICYQUALINFO *qual;
+	if(!(qual = POLICYQUALINFO_new())) goto merr;
+	qual->pqualid = OBJ_nid2obj(NID_id_qt_unotice);
+	if(!(not = USERNOTICE_new())) goto merr;
+	qual->d.usernotice = not;
+	for(i = 0; i < sk_num(unot); i++) {
+		cnf = (CONF_VALUE *)sk_value(unot, i);
+		if(!strcmp(cnf->name, "explicitText")) {
+			not->exptext = ASN1_VISIBLESTRING_new();
+			if(!ASN1_STRING_set(not->exptext, cnf->value,
+						 strlen(cnf->value))) goto merr;
+		} else if(!strcmp(cnf->name, "organization")) {
+			NOTICEREF *nref;
+			if(!not->noticeref) {
+				if(!(nref = NOTICEREF_new())) goto merr;
+				not->noticeref = nref;
+			} else nref = not->noticeref;
+			nref->organization = ASN1_VISIBLESTRING_new();
+			if(!ASN1_STRING_set(nref->organization, cnf->value,
+						 strlen(cnf->value))) goto merr;
+		} else if(!strcmp(cnf->name, "noticeNumbers")) {
+			NOTICEREF *nref;
+			STACK *nos;
+			if(!not->noticeref) {
+				if(!(nref = NOTICEREF_new())) goto merr;
+				not->noticeref = nref;
+			} else nref = not->noticeref;
+			nos = X509V3_parse_list(cnf->value);
+			if(!nos || !sk_num(nos)) {
+				X509V3err(X509V3_F_NOTICE_SECTION,X509V3_R_INVALID_NUMBERS);
+				X509V3_conf_err(cnf);
+				goto err;
+			}
+			nref->noticenos = nref_nos(nos);
+			sk_pop_free(nos, X509V3_conf_free);
+			if(!nref->noticenos) goto err;
+		} else {
+			X509V3err(X509V3_F_NOTICE_SECTION,X509V3_R_INVALID_OPTION);
+
+			X509V3_conf_err(cnf);
+			goto err;
+		}
+	}
+
+	if(not->noticeref && 
+	      (!not->noticeref->noticenos || !not->noticeref->organization)) {
+			X509V3err(X509V3_F_NOTICE_SECTION,X509V3_R_NEED_ORGANIZATION_AND_NUMBERS);
+			goto err;
+	}
+
+	return qual;
+
+	err:
+	POLICYQUALINFO_free(qual);
+	return NULL;
+
+	merr:
+	X509V3err(X509V3_F_NOTICE_SECTION,ERR_R_MALLOC_FAILURE);
+	POLICYQUALINFO_free(qual);
+	return NULL;
+}
+
+static STACK *nref_nos(nos)
+STACK *nos;
+{
+	STACK *nnums;
+	CONF_VALUE *cnf;
+	ASN1_INTEGER *aint;
+	int i;
+	if(!(nnums = sk_new_null())) goto merr;
+	for(i = 0; i < sk_num(nos); i++) {
+		cnf = (CONF_VALUE *)sk_value(nos, i);
+		if(!(aint = s2i_ASN1_INTEGER(NULL, cnf->name))) {
+			X509V3err(X509V3_F_NREF_NOS,X509V3_R_INVALID_NUMBER);
+			goto err;
+		}
+		if(!sk_push(nnums, (char *)aint)) goto merr;
+	}
+	return nnums;
+
+	err:
+	sk_pop_free(nnums, ASN1_STRING_free);
+	return NULL;
+
+	merr:
+	X509V3err(X509V3_F_NOTICE_SECTION,ERR_R_MALLOC_FAILURE);
+	sk_pop_free(nnums, ASN1_STRING_free);
 	return NULL;
 }
 
@@ -326,7 +487,7 @@
 		BIO_puts(out, "\n");
 	}
 	if(notice->exptext)
-		BIO_printf(out, "%*sNotice Reference: %s\n", indent, "",
+		BIO_printf(out, "%*sExplicit Text: %s\n", indent, "",
 							 notice->exptext->data);
 }
 		
diff --git a/crypto/x509v3/v3err.c b/crypto/x509v3/v3err.c
index 4a8297c..2f6ed43 100644
--- a/crypto/x509v3/v3err.c
+++ b/crypto/x509v3/v3err.c
@@ -69,6 +69,9 @@
 {ERR_PACK(0,X509V3_F_HEX_TO_STRING,0),	"hex_to_string"},
 {ERR_PACK(0,X509V3_F_I2S_ASN1_ENUMERATED,0),	"i2s_ASN1_ENUMERATED"},
 {ERR_PACK(0,X509V3_F_I2S_ASN1_INTEGER,0),	"i2s_ASN1_INTEGER"},
+{ERR_PACK(0,X509V3_F_NOTICE_SECTION,0),	"NOTICE_SECTION"},
+{ERR_PACK(0,X509V3_F_NREF_NOS,0),	"NREF_NOS"},
+{ERR_PACK(0,X509V3_F_POLICY_SECTION,0),	"POLICY_SECTION"},
 {ERR_PACK(0,X509V3_F_R2I_CERTPOL,0),	"R2I_CERTPOL"},
 {ERR_PACK(0,X509V3_F_S2I_ASN1_IA5STRING,0),	"S2I_ASN1_IA5STRING"},
 {ERR_PACK(0,X509V3_F_S2I_ASN1_INTEGER,0),	"s2i_ASN1_INTEGER"},
@@ -106,6 +109,7 @@
 {X509V3_R_DUPLICATE_ZONE_ID              ,"duplicate zone id"},
 {X509V3_R_ERROR_CONVERTING_ZONE          ,"error converting zone"},
 {X509V3_R_ERROR_IN_EXTENSION             ,"error in extension"},
+{X509V3_R_EXPECTED_A_SECTION_NAME        ,"expected a section name"},
 {X509V3_R_EXTENSION_NAME_ERROR           ,"extension name error"},
 {X509V3_R_EXTENSION_NOT_FOUND            ,"extension not found"},
 {X509V3_R_EXTENSION_SETTING_NOT_SUPPORTED,"extension setting not supported"},
@@ -117,14 +121,19 @@
 {X509V3_R_INVALID_NULL_ARGUMENT          ,"invalid null argument"},
 {X509V3_R_INVALID_NULL_NAME              ,"invalid null name"},
 {X509V3_R_INVALID_NULL_VALUE             ,"invalid null value"},
+{X509V3_R_INVALID_NUMBER                 ,"invalid number"},
+{X509V3_R_INVALID_NUMBERS                ,"invalid numbers"},
 {X509V3_R_INVALID_OBJECT_IDENTIFIER      ,"invalid object identifier"},
+{X509V3_R_INVALID_OPTION                 ,"invalid option"},
 {X509V3_R_INVALID_POLICY_IDENTIFIER      ,"invalid policy identifier"},
 {X509V3_R_INVALID_SECTION                ,"invalid section"},
 {X509V3_R_ISSUER_DECODE_ERROR            ,"issuer decode error"},
 {X509V3_R_MISSING_VALUE                  ,"missing value"},
+{X509V3_R_NEED_ORGANIZATION_AND_NUMBERS  ,"need organization and numbers"},
 {X509V3_R_NO_CONFIG_DATABASE             ,"no config database"},
 {X509V3_R_NO_ISSUER_CERTIFICATE          ,"no issuer certificate"},
 {X509V3_R_NO_ISSUER_DETAILS              ,"no issuer details"},
+{X509V3_R_NO_POLICY_IDENTIFIER           ,"no policy identifier"},
 {X509V3_R_NO_PUBLIC_KEY                  ,"no public key"},
 {X509V3_R_NO_SUBJECT_DETAILS             ,"no subject details"},
 {X509V3_R_ODD_NUMBER_OF_DIGITS           ,"odd number of digits"},
diff --git a/crypto/x509v3/x509v3.err b/crypto/x509v3/x509v3.err
index 2c02781..bdb68d1 100644
--- a/crypto/x509v3/x509v3.err
+++ b/crypto/x509v3/x509v3.err
@@ -7,6 +7,9 @@
 #define X509V3_F_HEX_TO_STRING				 111
 #define X509V3_F_I2S_ASN1_ENUMERATED			 121
 #define X509V3_F_I2S_ASN1_INTEGER			 120
+#define X509V3_F_NOTICE_SECTION				 132
+#define X509V3_F_NREF_NOS				 133
+#define X509V3_F_POLICY_SECTION				 131
 #define X509V3_F_R2I_CERTPOL				 130
 #define X509V3_F_S2I_ASN1_IA5STRING			 100
 #define X509V3_F_S2I_ASN1_INTEGER			 108
@@ -41,6 +44,7 @@
 #define X509V3_R_DUPLICATE_ZONE_ID			 133
 #define X509V3_R_ERROR_CONVERTING_ZONE			 131
 #define X509V3_R_ERROR_IN_EXTENSION			 128
+#define X509V3_R_EXPECTED_A_SECTION_NAME		 137
 #define X509V3_R_EXTENSION_NAME_ERROR			 115
 #define X509V3_R_EXTENSION_NOT_FOUND			 102
 #define X509V3_R_EXTENSION_SETTING_NOT_SUPPORTED	 103
@@ -52,14 +56,19 @@
 #define X509V3_R_INVALID_NULL_ARGUMENT			 107
 #define X509V3_R_INVALID_NULL_NAME			 108
 #define X509V3_R_INVALID_NULL_VALUE			 109
+#define X509V3_R_INVALID_NUMBER				 140
+#define X509V3_R_INVALID_NUMBERS			 141
 #define X509V3_R_INVALID_OBJECT_IDENTIFIER		 110
+#define X509V3_R_INVALID_OPTION				 138
 #define X509V3_R_INVALID_POLICY_IDENTIFIER		 134
 #define X509V3_R_INVALID_SECTION			 135
 #define X509V3_R_ISSUER_DECODE_ERROR			 126
 #define X509V3_R_MISSING_VALUE				 124
+#define X509V3_R_NEED_ORGANIZATION_AND_NUMBERS		 142
 #define X509V3_R_NO_CONFIG_DATABASE			 136
 #define X509V3_R_NO_ISSUER_CERTIFICATE			 121
 #define X509V3_R_NO_ISSUER_DETAILS			 127
+#define X509V3_R_NO_POLICY_IDENTIFIER			 139
 #define X509V3_R_NO_PUBLIC_KEY				 114
 #define X509V3_R_NO_SUBJECT_DETAILS			 125
 #define X509V3_R_ODD_NUMBER_OF_DIGITS			 112
diff --git a/crypto/x509v3/x509v3.h b/crypto/x509v3/x509v3.h
index 8ebbea2..6c3937d 100644
--- a/crypto/x509v3/x509v3.h
+++ b/crypto/x509v3/x509v3.h
@@ -515,6 +515,9 @@
 #define X509V3_F_HEX_TO_STRING				 111
 #define X509V3_F_I2S_ASN1_ENUMERATED			 121
 #define X509V3_F_I2S_ASN1_INTEGER			 120
+#define X509V3_F_NOTICE_SECTION				 132
+#define X509V3_F_NREF_NOS				 133
+#define X509V3_F_POLICY_SECTION				 131
 #define X509V3_F_R2I_CERTPOL				 130
 #define X509V3_F_S2I_ASN1_IA5STRING			 100
 #define X509V3_F_S2I_ASN1_INTEGER			 108
@@ -549,6 +552,7 @@
 #define X509V3_R_DUPLICATE_ZONE_ID			 133
 #define X509V3_R_ERROR_CONVERTING_ZONE			 131
 #define X509V3_R_ERROR_IN_EXTENSION			 128
+#define X509V3_R_EXPECTED_A_SECTION_NAME		 137
 #define X509V3_R_EXTENSION_NAME_ERROR			 115
 #define X509V3_R_EXTENSION_NOT_FOUND			 102
 #define X509V3_R_EXTENSION_SETTING_NOT_SUPPORTED	 103
@@ -560,14 +564,19 @@
 #define X509V3_R_INVALID_NULL_ARGUMENT			 107
 #define X509V3_R_INVALID_NULL_NAME			 108
 #define X509V3_R_INVALID_NULL_VALUE			 109
+#define X509V3_R_INVALID_NUMBER				 140
+#define X509V3_R_INVALID_NUMBERS			 141
 #define X509V3_R_INVALID_OBJECT_IDENTIFIER		 110
+#define X509V3_R_INVALID_OPTION				 138
 #define X509V3_R_INVALID_POLICY_IDENTIFIER		 134
 #define X509V3_R_INVALID_SECTION			 135
 #define X509V3_R_ISSUER_DECODE_ERROR			 126
 #define X509V3_R_MISSING_VALUE				 124
+#define X509V3_R_NEED_ORGANIZATION_AND_NUMBERS		 142
 #define X509V3_R_NO_CONFIG_DATABASE			 136
 #define X509V3_R_NO_ISSUER_CERTIFICATE			 121
 #define X509V3_R_NO_ISSUER_DETAILS			 127
+#define X509V3_R_NO_POLICY_IDENTIFIER			 139
 #define X509V3_R_NO_PUBLIC_KEY				 114
 #define X509V3_R_NO_SUBJECT_DETAILS			 125
 #define X509V3_R_ODD_NUMBER_OF_DIGITS			 112