1295009Sjkim/* v3_pci.c */
2280297Sjkim/*
3280297Sjkim * Contributed to the OpenSSL Project 2004 by Richard Levitte
4280297Sjkim * (richard@levitte.org)
5160814Ssimon */
6291719Sjkim/* Copyright (c) 2004 Kungliga Tekniska H��gskolan
7160814Ssimon * (Royal Institute of Technology, Stockholm, Sweden).
8160814Ssimon * All rights reserved.
9160814Ssimon *
10160814Ssimon * Redistribution and use in source and binary forms, with or without
11160814Ssimon * modification, are permitted provided that the following conditions
12160814Ssimon * are met:
13160814Ssimon *
14160814Ssimon * 1. Redistributions of source code must retain the above copyright
15160814Ssimon *    notice, this list of conditions and the following disclaimer.
16160814Ssimon *
17160814Ssimon * 2. Redistributions in binary form must reproduce the above copyright
18160814Ssimon *    notice, this list of conditions and the following disclaimer in the
19160814Ssimon *    documentation and/or other materials provided with the distribution.
20160814Ssimon *
21160814Ssimon * 3. Neither the name of the Institute nor the names of its contributors
22160814Ssimon *    may be used to endorse or promote products derived from this software
23160814Ssimon *    without specific prior written permission.
24160814Ssimon *
25160814Ssimon * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
26160814Ssimon * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27160814Ssimon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28160814Ssimon * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
29160814Ssimon * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30160814Ssimon * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31160814Ssimon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32160814Ssimon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33160814Ssimon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34160814Ssimon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35160814Ssimon * SUCH DAMAGE.
36160814Ssimon */
37160814Ssimon
38160814Ssimon#include <stdio.h>
39160814Ssimon#include "cryptlib.h"
40160814Ssimon#include <openssl/conf.h>
41160814Ssimon#include <openssl/x509v3.h>
42160814Ssimon
43160814Ssimonstatic int i2r_pci(X509V3_EXT_METHOD *method, PROXY_CERT_INFO_EXTENSION *ext,
44280297Sjkim                   BIO *out, int indent);
45160814Ssimonstatic PROXY_CERT_INFO_EXTENSION *r2i_pci(X509V3_EXT_METHOD *method,
46280297Sjkim                                          X509V3_CTX *ctx, char *str);
47160814Ssimon
48167612Ssimonconst X509V3_EXT_METHOD v3_pci =
49280297Sjkim    { NID_proxyCertInfo, 0, ASN1_ITEM_ref(PROXY_CERT_INFO_EXTENSION),
50280297Sjkim    0, 0, 0, 0,
51280297Sjkim    0, 0,
52280297Sjkim    NULL, NULL,
53280297Sjkim    (X509V3_EXT_I2R)i2r_pci,
54280297Sjkim    (X509V3_EXT_R2I)r2i_pci,
55280297Sjkim    NULL,
56280297Sjkim};
57160814Ssimon
58160814Ssimonstatic int i2r_pci(X509V3_EXT_METHOD *method, PROXY_CERT_INFO_EXTENSION *pci,
59280297Sjkim                   BIO *out, int indent)
60280297Sjkim{
61280297Sjkim    BIO_printf(out, "%*sPath Length Constraint: ", indent, "");
62280297Sjkim    if (pci->pcPathLengthConstraint)
63280297Sjkim        i2a_ASN1_INTEGER(out, pci->pcPathLengthConstraint);
64280297Sjkim    else
65280297Sjkim        BIO_printf(out, "infinite");
66280297Sjkim    BIO_puts(out, "\n");
67280297Sjkim    BIO_printf(out, "%*sPolicy Language: ", indent, "");
68280297Sjkim    i2a_ASN1_OBJECT(out, pci->proxyPolicy->policyLanguage);
69280297Sjkim    BIO_puts(out, "\n");
70280297Sjkim    if (pci->proxyPolicy->policy && pci->proxyPolicy->policy->data)
71280297Sjkim        BIO_printf(out, "%*sPolicy Text: %s\n", indent, "",
72280297Sjkim                   pci->proxyPolicy->policy->data);
73280297Sjkim    return 1;
74280297Sjkim}
75160814Ssimon
76160814Ssimonstatic int process_pci_value(CONF_VALUE *val,
77280297Sjkim                             ASN1_OBJECT **language, ASN1_INTEGER **pathlen,
78280297Sjkim                             ASN1_OCTET_STRING **policy)
79280297Sjkim{
80280297Sjkim    int free_policy = 0;
81160814Ssimon
82280297Sjkim    if (strcmp(val->name, "language") == 0) {
83280297Sjkim        if (*language) {
84280297Sjkim            X509V3err(X509V3_F_PROCESS_PCI_VALUE,
85280297Sjkim                      X509V3_R_POLICY_LANGUAGE_ALREADY_DEFINED);
86280297Sjkim            X509V3_conf_err(val);
87280297Sjkim            return 0;
88280297Sjkim        }
89280297Sjkim        if (!(*language = OBJ_txt2obj(val->value, 0))) {
90280297Sjkim            X509V3err(X509V3_F_PROCESS_PCI_VALUE,
91280297Sjkim                      X509V3_R_INVALID_OBJECT_IDENTIFIER);
92280297Sjkim            X509V3_conf_err(val);
93280297Sjkim            return 0;
94280297Sjkim        }
95280297Sjkim    } else if (strcmp(val->name, "pathlen") == 0) {
96280297Sjkim        if (*pathlen) {
97280297Sjkim            X509V3err(X509V3_F_PROCESS_PCI_VALUE,
98280297Sjkim                      X509V3_R_POLICY_PATH_LENGTH_ALREADY_DEFINED);
99280297Sjkim            X509V3_conf_err(val);
100280297Sjkim            return 0;
101280297Sjkim        }
102280297Sjkim        if (!X509V3_get_value_int(val, pathlen)) {
103280297Sjkim            X509V3err(X509V3_F_PROCESS_PCI_VALUE,
104280297Sjkim                      X509V3_R_POLICY_PATH_LENGTH);
105280297Sjkim            X509V3_conf_err(val);
106280297Sjkim            return 0;
107280297Sjkim        }
108280297Sjkim    } else if (strcmp(val->name, "policy") == 0) {
109280297Sjkim        unsigned char *tmp_data = NULL;
110280297Sjkim        long val_len;
111280297Sjkim        if (!*policy) {
112280297Sjkim            *policy = ASN1_OCTET_STRING_new();
113280297Sjkim            if (!*policy) {
114280297Sjkim                X509V3err(X509V3_F_PROCESS_PCI_VALUE, ERR_R_MALLOC_FAILURE);
115280297Sjkim                X509V3_conf_err(val);
116280297Sjkim                return 0;
117280297Sjkim            }
118280297Sjkim            free_policy = 1;
119280297Sjkim        }
120280297Sjkim        if (strncmp(val->value, "hex:", 4) == 0) {
121280297Sjkim            unsigned char *tmp_data2 =
122280297Sjkim                string_to_hex(val->value + 4, &val_len);
123160814Ssimon
124280297Sjkim            if (!tmp_data2) {
125280297Sjkim                X509V3err(X509V3_F_PROCESS_PCI_VALUE,
126280297Sjkim                          X509V3_R_ILLEGAL_HEX_DIGIT);
127280297Sjkim                X509V3_conf_err(val);
128280297Sjkim                goto err;
129280297Sjkim            }
130160814Ssimon
131280297Sjkim            tmp_data = OPENSSL_realloc((*policy)->data,
132280297Sjkim                                       (*policy)->length + val_len + 1);
133280297Sjkim            if (tmp_data) {
134280297Sjkim                (*policy)->data = tmp_data;
135280297Sjkim                memcpy(&(*policy)->data[(*policy)->length],
136280297Sjkim                       tmp_data2, val_len);
137280297Sjkim                (*policy)->length += val_len;
138280297Sjkim                (*policy)->data[(*policy)->length] = '\0';
139280297Sjkim            } else {
140280297Sjkim                OPENSSL_free(tmp_data2);
141280297Sjkim                /*
142280297Sjkim                 * realloc failure implies the original data space is b0rked
143280297Sjkim                 * too!
144280297Sjkim                 */
145280297Sjkim                (*policy)->data = NULL;
146280297Sjkim                (*policy)->length = 0;
147280297Sjkim                X509V3err(X509V3_F_PROCESS_PCI_VALUE, ERR_R_MALLOC_FAILURE);
148280297Sjkim                X509V3_conf_err(val);
149280297Sjkim                goto err;
150280297Sjkim            }
151280297Sjkim            OPENSSL_free(tmp_data2);
152280297Sjkim        } else if (strncmp(val->value, "file:", 5) == 0) {
153280297Sjkim            unsigned char buf[2048];
154280297Sjkim            int n;
155280297Sjkim            BIO *b = BIO_new_file(val->value + 5, "r");
156280297Sjkim            if (!b) {
157280297Sjkim                X509V3err(X509V3_F_PROCESS_PCI_VALUE, ERR_R_BIO_LIB);
158280297Sjkim                X509V3_conf_err(val);
159280297Sjkim                goto err;
160280297Sjkim            }
161280297Sjkim            while ((n = BIO_read(b, buf, sizeof(buf))) > 0
162280297Sjkim                   || (n == 0 && BIO_should_retry(b))) {
163280297Sjkim                if (!n)
164280297Sjkim                    continue;
165160814Ssimon
166280297Sjkim                tmp_data = OPENSSL_realloc((*policy)->data,
167280297Sjkim                                           (*policy)->length + n + 1);
168160814Ssimon
169280297Sjkim                if (!tmp_data)
170280297Sjkim                    break;
171160814Ssimon
172280297Sjkim                (*policy)->data = tmp_data;
173280297Sjkim                memcpy(&(*policy)->data[(*policy)->length], buf, n);
174280297Sjkim                (*policy)->length += n;
175280297Sjkim                (*policy)->data[(*policy)->length] = '\0';
176280297Sjkim            }
177280297Sjkim            BIO_free_all(b);
178160814Ssimon
179280297Sjkim            if (n < 0) {
180280297Sjkim                X509V3err(X509V3_F_PROCESS_PCI_VALUE, ERR_R_BIO_LIB);
181280297Sjkim                X509V3_conf_err(val);
182280297Sjkim                goto err;
183280297Sjkim            }
184280297Sjkim        } else if (strncmp(val->value, "text:", 5) == 0) {
185280297Sjkim            val_len = strlen(val->value + 5);
186280297Sjkim            tmp_data = OPENSSL_realloc((*policy)->data,
187280297Sjkim                                       (*policy)->length + val_len + 1);
188280297Sjkim            if (tmp_data) {
189280297Sjkim                (*policy)->data = tmp_data;
190280297Sjkim                memcpy(&(*policy)->data[(*policy)->length],
191280297Sjkim                       val->value + 5, val_len);
192280297Sjkim                (*policy)->length += val_len;
193280297Sjkim                (*policy)->data[(*policy)->length] = '\0';
194280297Sjkim            } else {
195280297Sjkim                /*
196280297Sjkim                 * realloc failure implies the original data space is b0rked
197280297Sjkim                 * too!
198280297Sjkim                 */
199280297Sjkim                (*policy)->data = NULL;
200280297Sjkim                (*policy)->length = 0;
201280297Sjkim                X509V3err(X509V3_F_PROCESS_PCI_VALUE, ERR_R_MALLOC_FAILURE);
202280297Sjkim                X509V3_conf_err(val);
203280297Sjkim                goto err;
204280297Sjkim            }
205280297Sjkim        } else {
206280297Sjkim            X509V3err(X509V3_F_PROCESS_PCI_VALUE,
207280297Sjkim                      X509V3_R_INCORRECT_POLICY_SYNTAX_TAG);
208280297Sjkim            X509V3_conf_err(val);
209280297Sjkim            goto err;
210280297Sjkim        }
211280297Sjkim        if (!tmp_data) {
212280297Sjkim            X509V3err(X509V3_F_PROCESS_PCI_VALUE, ERR_R_MALLOC_FAILURE);
213280297Sjkim            X509V3_conf_err(val);
214280297Sjkim            goto err;
215280297Sjkim        }
216280297Sjkim    }
217280297Sjkim    return 1;
218280297Sjkim err:
219280297Sjkim    if (free_policy) {
220280297Sjkim        ASN1_OCTET_STRING_free(*policy);
221280297Sjkim        *policy = NULL;
222280297Sjkim    }
223280297Sjkim    return 0;
224280297Sjkim}
225160814Ssimon
226160814Ssimonstatic PROXY_CERT_INFO_EXTENSION *r2i_pci(X509V3_EXT_METHOD *method,
227280297Sjkim                                          X509V3_CTX *ctx, char *value)
228280297Sjkim{
229280297Sjkim    PROXY_CERT_INFO_EXTENSION *pci = NULL;
230280297Sjkim    STACK_OF(CONF_VALUE) *vals;
231280297Sjkim    ASN1_OBJECT *language = NULL;
232280297Sjkim    ASN1_INTEGER *pathlen = NULL;
233280297Sjkim    ASN1_OCTET_STRING *policy = NULL;
234280297Sjkim    int i, j;
235160814Ssimon
236280297Sjkim    vals = X509V3_parse_list(value);
237280297Sjkim    for (i = 0; i < sk_CONF_VALUE_num(vals); i++) {
238280297Sjkim        CONF_VALUE *cnf = sk_CONF_VALUE_value(vals, i);
239280297Sjkim        if (!cnf->name || (*cnf->name != '@' && !cnf->value)) {
240280297Sjkim            X509V3err(X509V3_F_R2I_PCI,
241280297Sjkim                      X509V3_R_INVALID_PROXY_POLICY_SETTING);
242280297Sjkim            X509V3_conf_err(cnf);
243280297Sjkim            goto err;
244280297Sjkim        }
245280297Sjkim        if (*cnf->name == '@') {
246280297Sjkim            STACK_OF(CONF_VALUE) *sect;
247280297Sjkim            int success_p = 1;
248160814Ssimon
249280297Sjkim            sect = X509V3_get_section(ctx, cnf->name + 1);
250280297Sjkim            if (!sect) {
251280297Sjkim                X509V3err(X509V3_F_R2I_PCI, X509V3_R_INVALID_SECTION);
252280297Sjkim                X509V3_conf_err(cnf);
253280297Sjkim                goto err;
254280297Sjkim            }
255280297Sjkim            for (j = 0; success_p && j < sk_CONF_VALUE_num(sect); j++) {
256280297Sjkim                success_p =
257280297Sjkim                    process_pci_value(sk_CONF_VALUE_value(sect, j),
258280297Sjkim                                      &language, &pathlen, &policy);
259280297Sjkim            }
260280297Sjkim            X509V3_section_free(ctx, sect);
261280297Sjkim            if (!success_p)
262280297Sjkim                goto err;
263280297Sjkim        } else {
264280297Sjkim            if (!process_pci_value(cnf, &language, &pathlen, &policy)) {
265280297Sjkim                X509V3_conf_err(cnf);
266280297Sjkim                goto err;
267280297Sjkim            }
268280297Sjkim        }
269280297Sjkim    }
270160814Ssimon
271280297Sjkim    /* Language is mandatory */
272280297Sjkim    if (!language) {
273280297Sjkim        X509V3err(X509V3_F_R2I_PCI,
274280297Sjkim                  X509V3_R_NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED);
275280297Sjkim        goto err;
276280297Sjkim    }
277280297Sjkim    i = OBJ_obj2nid(language);
278280297Sjkim    if ((i == NID_Independent || i == NID_id_ppl_inheritAll) && policy) {
279280297Sjkim        X509V3err(X509V3_F_R2I_PCI,
280280297Sjkim                  X509V3_R_POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY);
281280297Sjkim        goto err;
282280297Sjkim    }
283160814Ssimon
284280297Sjkim    pci = PROXY_CERT_INFO_EXTENSION_new();
285280297Sjkim    if (!pci) {
286280297Sjkim        X509V3err(X509V3_F_R2I_PCI, ERR_R_MALLOC_FAILURE);
287280297Sjkim        goto err;
288280297Sjkim    }
289160814Ssimon
290280297Sjkim    pci->proxyPolicy->policyLanguage = language;
291280297Sjkim    language = NULL;
292280297Sjkim    pci->proxyPolicy->policy = policy;
293280297Sjkim    policy = NULL;
294280297Sjkim    pci->pcPathLengthConstraint = pathlen;
295280297Sjkim    pathlen = NULL;
296280297Sjkim    goto end;
297280297Sjkim err:
298280297Sjkim    if (language) {
299280297Sjkim        ASN1_OBJECT_free(language);
300280297Sjkim        language = NULL;
301280297Sjkim    }
302280297Sjkim    if (pathlen) {
303280297Sjkim        ASN1_INTEGER_free(pathlen);
304280297Sjkim        pathlen = NULL;
305280297Sjkim    }
306280297Sjkim    if (policy) {
307280297Sjkim        ASN1_OCTET_STRING_free(policy);
308280297Sjkim        policy = NULL;
309280297Sjkim    }
310280297Sjkim    if (pci) {
311280297Sjkim        PROXY_CERT_INFO_EXTENSION_free(pci);
312280297Sjkim        pci = NULL;
313280297Sjkim    }
314280297Sjkim end:
315280297Sjkim    sk_CONF_VALUE_pop_free(vals, X509V3_conf_free);
316280297Sjkim    return pci;
317280297Sjkim}
318