Add support for freshest CRL extension.
[openssl.git] / crypto / x509v3 / v3_crld.c
index bdb3dd523bc0bca24136a4df07baecd78074ed43..001edec39a446f6f318ef93971068d5268639f0f 100644 (file)
@@ -3,7 +3,7 @@
  * project 1999.
  */
 /* ====================================================================
- * Copyright (c) 1999, 2005 The OpenSSL Project.  All rights reserved.
+ * Copyright (c) 1999-2008 The OpenSSL Project.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -68,7 +68,7 @@ static void *v2i_crld(X509V3_EXT_METHOD *method,
 static int i2r_crldp(X509V3_EXT_METHOD *method, void *pcrldp, BIO *out,
                                                                int indent);
 
-X509V3_EXT_METHOD v3_crld =
+const X509V3_EXT_METHOD v3_crld =
        {
        NID_crl_distribution_points, 0, ASN1_ITEM_ref(CRL_DIST_POINTS),
        0,0,0,0,
@@ -79,6 +79,17 @@ X509V3_EXT_METHOD v3_crld =
        NULL
        };
 
+const X509V3_EXT_METHOD v3_freshest_crl =
+       {
+       NID_freshest_crl, 0, ASN1_ITEM_ref(CRL_DIST_POINTS),
+       0,0,0,0,
+       0,0,
+       0,
+       v2i_crld,
+       i2r_crldp,0,
+       NULL
+       };
+
 static STACK_OF(GENERAL_NAME) *gnames_from_sectname(X509V3_CTX *ctx, char *sect)
        {
        STACK_OF(CONF_VALUE) *gnsect;
@@ -101,7 +112,7 @@ static STACK_OF(GENERAL_NAME) *gnames_from_sectname(X509V3_CTX *ctx, char *sect)
        return gens;
        }
 
-static int get_dist_point_name(DIST_POINT_NAME **pdp, X509V3_CTX *ctx,
+static int set_dist_point_name(DIST_POINT_NAME **pdp, X509V3_CTX *ctx,
                                                        CONF_VALUE *cnf)
        {
        STACK_OF(GENERAL_NAME) *fnm = NULL;
@@ -123,7 +134,7 @@ static int get_dist_point_name(DIST_POINT_NAME **pdp, X509V3_CTX *ctx,
                dnsect = X509V3_get_section(ctx, cnf->value);
                if (!dnsect)
                        {
-                       X509V3err(X509V3_F_GET_DIST_POINT_NAME,
+                       X509V3err(X509V3_F_SET_DIST_POINT_NAME,
                                                X509V3_R_SECTION_NOT_FOUND);
                        return -1;
                        }
@@ -140,7 +151,7 @@ static int get_dist_point_name(DIST_POINT_NAME **pdp, X509V3_CTX *ctx,
                if (sk_X509_NAME_ENTRY_value(rnm,
                                sk_X509_NAME_ENTRY_num(rnm) - 1)->set)
                        {
-                       X509V3err(X509V3_F_GET_DIST_POINT_NAME,
+                       X509V3err(X509V3_F_SET_DIST_POINT_NAME,
                                                X509V3_R_INVAID_MULTIPLE_RDNS);
                        goto err;
                        }
@@ -150,7 +161,7 @@ static int get_dist_point_name(DIST_POINT_NAME **pdp, X509V3_CTX *ctx,
 
        if (*pdp)
                {
-               X509V3err(X509V3_F_GET_DIST_POINT_NAME,
+               X509V3err(X509V3_F_SET_DIST_POINT_NAME,
                                                X509V3_R_DISTPOINT_ALREADY_SET);
                goto err;
                }
@@ -179,7 +190,6 @@ static int get_dist_point_name(DIST_POINT_NAME **pdp, X509V3_CTX *ctx,
        return -1;
        }
 
-
 static const BIT_STRING_BITNAME reason_flags[] = {
 {1, "Key Compromise", "keyCompromise"},
 {2, "CA Compromise", "CACompromise"},
@@ -269,7 +279,7 @@ static DIST_POINT *crldp_from_section(X509V3_CTX *ctx,
                {
                int ret;
                cnf = sk_CONF_VALUE_value(nval, i);
-               ret = get_dist_point_name(&point->distpoint, ctx, cnf);
+               ret = set_dist_point_name(&point->distpoint, ctx, cnf);
                if (ret > 0)
                        continue;
                if (ret < 0)
@@ -309,10 +319,10 @@ static void *v2i_crld(X509V3_EXT_METHOD *method,
        for(i = 0; i < sk_CONF_VALUE_num(nval); i++) {
                DIST_POINT *point;
                cnf = sk_CONF_VALUE_value(nval, i);
-               if (!cnf->value && cnf->name[0] == '@')
+               if (!cnf->value)
                        {
                        STACK_OF(CONF_VALUE) *dpsect;
-                       dpsect = X509V3_get_section(ctx, cnf->name + 1);
+                       dpsect = X509V3_get_section(ctx, cnf->name);
                        if (!dpsect)
                                goto err;
                        point = crldp_from_section(ctx, dpsect);
@@ -362,11 +372,31 @@ static void *v2i_crld(X509V3_EXT_METHOD *method,
 IMPLEMENT_STACK_OF(DIST_POINT)
 IMPLEMENT_ASN1_SET_OF(DIST_POINT)
 
+static int dpn_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
+                                                               void *exarg)
+       {
+       DIST_POINT_NAME *dpn = (DIST_POINT_NAME *)*pval;
 
-ASN1_CHOICE(DIST_POINT_NAME) = {
+       switch(operation)
+               {
+               case ASN1_OP_NEW_POST:
+               dpn->dpname = NULL;
+               break;
+
+               case ASN1_OP_FREE_POST:
+               if (dpn->dpname)
+                       X509_NAME_free(dpn->dpname);
+               break;
+               }
+       return 1;
+       }
+
+
+ASN1_CHOICE_cb(DIST_POINT_NAME, dpn_cb) = {
        ASN1_IMP_SEQUENCE_OF(DIST_POINT_NAME, name.fullname, GENERAL_NAME, 0),
        ASN1_IMP_SET_OF(DIST_POINT_NAME, name.relativename, X509_NAME_ENTRY, 1)
-} ASN1_CHOICE_END(DIST_POINT_NAME)
+} ASN1_CHOICE_END_cb(DIST_POINT_NAME, DIST_POINT_NAME, type)
+
 
 IMPLEMENT_ASN1_FUNCTIONS(DIST_POINT_NAME)
 
@@ -393,20 +423,86 @@ ASN1_SEQUENCE(ISSUING_DIST_POINT) = {
        ASN1_IMP_OPT(ISSUING_DIST_POINT, onlyattr, ASN1_FBOOLEAN, 5)
 } ASN1_SEQUENCE_END(ISSUING_DIST_POINT)
 
+IMPLEMENT_ASN1_FUNCTIONS(ISSUING_DIST_POINT)
+
 static int i2r_idp(X509V3_EXT_METHOD *method,
             void *pidp, BIO *out, int indent);
+static void *v2i_idp(X509V3_EXT_METHOD *method,
+                               X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval);
 
-X509V3_EXT_METHOD v3_idp =
+const X509V3_EXT_METHOD v3_idp =
        {
        NID_issuing_distribution_point, X509V3_EXT_MULTILINE,
        ASN1_ITEM_ref(ISSUING_DIST_POINT),
        0,0,0,0,
        0,0,
-       0,0,
+       0,
+       v2i_idp,
        i2r_idp,0,
        NULL
        };
 
+static void *v2i_idp(X509V3_EXT_METHOD *method,
+                               X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval)
+       {
+       ISSUING_DIST_POINT *idp = NULL;
+       CONF_VALUE *cnf;
+       char *name, *val;
+       int i, ret;
+       idp = ISSUING_DIST_POINT_new();
+       if (!idp)
+               goto merr;
+       for(i = 0; i < sk_CONF_VALUE_num(nval); i++)
+               {
+               cnf = sk_CONF_VALUE_value(nval, i);
+               name = cnf->name;
+               val = cnf->value;
+               ret = set_dist_point_name(&idp->distpoint, ctx, cnf);
+               if (ret > 0)
+                       continue;
+               if (ret < 0)
+                       goto err;
+               if (!strcmp(name, "onlyuser"))
+                       {
+                       if (!X509V3_get_value_bool(cnf, &idp->onlyuser))
+                               goto err;
+                       }
+               else if (!strcmp(name, "onlyCA"))
+                       {
+                       if (!X509V3_get_value_bool(cnf, &idp->onlyCA))
+                               goto err;
+                       }
+               else if (!strcmp(name, "onlyAA"))
+                       {
+                       if (!X509V3_get_value_bool(cnf, &idp->onlyattr))
+                               goto err;
+                       }
+               else if (!strcmp(name, "indirectCRL"))
+                       {
+                       if (!X509V3_get_value_bool(cnf, &idp->indirectCRL))
+                               goto err;
+                       }
+               else if (!strcmp(name, "onlysomereasons"))
+                       {
+                       if (!set_reasons(&idp->onlysomereasons, val))
+                               goto err;
+                       }
+               else
+                       {
+                        X509V3err(X509V3_F_V2I_IDP, X509V3_R_INVALID_NAME);
+                        X509V3_conf_err(cnf);
+                        goto err;
+                       }
+               }
+       return idp;
+
+       merr:
+       X509V3err(X509V3_F_V2I_IDP,ERR_R_MALLOC_FAILURE);
+       err:
+       ISSUING_DIST_POINT_free(idp);
+       return NULL;
+       }
+
 static int print_gens(BIO *out, STACK_OF(GENERAL_NAME) *gens, int indent)
        {
        int i;
@@ -485,3 +581,34 @@ static int i2r_crldp(X509V3_EXT_METHOD *method, void *pcrldp, BIO *out,
                }
        return 1;
        }
+
+int DIST_POINT_set_dpname(DIST_POINT_NAME *dpn, X509_NAME *iname)
+       {
+       int i;
+       STACK_OF(X509_NAME_ENTRY) *frag;
+       X509_NAME_ENTRY *ne;
+       if (!dpn || (dpn->type != 1))
+               return 1;
+       frag = dpn->name.relativename;
+       dpn->dpname = X509_NAME_dup(iname);
+       if (!dpn->dpname)
+               return 0;
+       for (i = 0; i < sk_X509_NAME_ENTRY_num(frag); i++)
+               {
+               ne = sk_X509_NAME_ENTRY_value(frag, i);
+               if (!X509_NAME_add_entry(dpn->dpname, ne, -1, i ? 0 : 1))
+                       {
+                       X509_NAME_free(dpn->dpname);
+                       dpn->dpname = NULL;
+                       return 0;
+                       }
+               }
+       /* generate cached encoding of name */
+       if (i2d_X509_NAME(dpn->dpname, NULL) < 0)
+               {
+               X509_NAME_free(dpn->dpname);
+               dpn->dpname = NULL;
+               return 0;
+               }
+       return 1;
+       }