v3_pci.c revision 296465
1/* v3_pci.c -*- mode:C; c-file-style: "eay" -*- */
2/*
3 * Contributed to the OpenSSL Project 2004 by Richard Levitte
4 * (richard@levitte.org)
5 */
6/* Copyright (c) 2004 Kungliga Tekniska H�gskolan
7 * (Royal Institute of Technology, Stockholm, Sweden).
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 *
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 *
17 * 2. Redistributions in binary form must reproduce the above copyright
18 *    notice, this list of conditions and the following disclaimer in the
19 *    documentation and/or other materials provided with the distribution.
20 *
21 * 3. Neither the name of the Institute nor the names of its contributors
22 *    may be used to endorse or promote products derived from this software
23 *    without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 */
37
38#include <stdio.h>
39#include "cryptlib.h"
40#include <openssl/conf.h>
41#include <openssl/x509v3.h>
42
43static int i2r_pci(X509V3_EXT_METHOD *method, PROXY_CERT_INFO_EXTENSION *ext,
44                   BIO *out, int indent);
45static PROXY_CERT_INFO_EXTENSION *r2i_pci(X509V3_EXT_METHOD *method,
46                                          X509V3_CTX *ctx, char *str);
47
48const X509V3_EXT_METHOD v3_pci =
49    { NID_proxyCertInfo, 0, ASN1_ITEM_ref(PROXY_CERT_INFO_EXTENSION),
50    0, 0, 0, 0,
51    0, 0,
52    NULL, NULL,
53    (X509V3_EXT_I2R)i2r_pci,
54    (X509V3_EXT_R2I)r2i_pci,
55    NULL,
56};
57
58static int i2r_pci(X509V3_EXT_METHOD *method, PROXY_CERT_INFO_EXTENSION *pci,
59                   BIO *out, int indent)
60{
61    BIO_printf(out, "%*sPath Length Constraint: ", indent, "");
62    if (pci->pcPathLengthConstraint)
63        i2a_ASN1_INTEGER(out, pci->pcPathLengthConstraint);
64    else
65        BIO_printf(out, "infinite");
66    BIO_puts(out, "\n");
67    BIO_printf(out, "%*sPolicy Language: ", indent, "");
68    i2a_ASN1_OBJECT(out, pci->proxyPolicy->policyLanguage);
69    BIO_puts(out, "\n");
70    if (pci->proxyPolicy->policy && pci->proxyPolicy->policy->data)
71        BIO_printf(out, "%*sPolicy Text: %s\n", indent, "",
72                   pci->proxyPolicy->policy->data);
73    return 1;
74}
75
76static int process_pci_value(CONF_VALUE *val,
77                             ASN1_OBJECT **language, ASN1_INTEGER **pathlen,
78                             ASN1_OCTET_STRING **policy)
79{
80    int free_policy = 0;
81
82    if (strcmp(val->name, "language") == 0) {
83        if (*language) {
84            X509V3err(X509V3_F_PROCESS_PCI_VALUE,
85                      X509V3_R_POLICY_LANGUAGE_ALREADTY_DEFINED);
86            X509V3_conf_err(val);
87            return 0;
88        }
89        if (!(*language = OBJ_txt2obj(val->value, 0))) {
90            X509V3err(X509V3_F_PROCESS_PCI_VALUE,
91                      X509V3_R_INVALID_OBJECT_IDENTIFIER);
92            X509V3_conf_err(val);
93            return 0;
94        }
95    } else if (strcmp(val->name, "pathlen") == 0) {
96        if (*pathlen) {
97            X509V3err(X509V3_F_PROCESS_PCI_VALUE,
98                      X509V3_R_POLICY_PATH_LENGTH_ALREADTY_DEFINED);
99            X509V3_conf_err(val);
100            return 0;
101        }
102        if (!X509V3_get_value_int(val, pathlen)) {
103            X509V3err(X509V3_F_PROCESS_PCI_VALUE,
104                      X509V3_R_POLICY_PATH_LENGTH);
105            X509V3_conf_err(val);
106            return 0;
107        }
108    } else if (strcmp(val->name, "policy") == 0) {
109        unsigned char *tmp_data = NULL;
110        long val_len;
111        if (!*policy) {
112            *policy = ASN1_OCTET_STRING_new();
113            if (!*policy) {
114                X509V3err(X509V3_F_PROCESS_PCI_VALUE, ERR_R_MALLOC_FAILURE);
115                X509V3_conf_err(val);
116                return 0;
117            }
118            free_policy = 1;
119        }
120        if (strncmp(val->value, "hex:", 4) == 0) {
121            unsigned char *tmp_data2 =
122                string_to_hex(val->value + 4, &val_len);
123
124            if (!tmp_data2) {
125                X509V3err(X509V3_F_PROCESS_PCI_VALUE,
126                          X509V3_R_ILLEGAL_HEX_DIGIT);
127                X509V3_conf_err(val);
128                goto err;
129            }
130
131            tmp_data = OPENSSL_realloc((*policy)->data,
132                                       (*policy)->length + val_len + 1);
133            if (tmp_data) {
134                (*policy)->data = tmp_data;
135                memcpy(&(*policy)->data[(*policy)->length],
136                       tmp_data2, val_len);
137                (*policy)->length += val_len;
138                (*policy)->data[(*policy)->length] = '\0';
139            } else {
140                OPENSSL_free(tmp_data2);
141                /*
142                 * realloc failure implies the original data space is b0rked
143                 * too!
144                 */
145                (*policy)->data = NULL;
146                (*policy)->length = 0;
147                X509V3err(X509V3_F_PROCESS_PCI_VALUE, ERR_R_MALLOC_FAILURE);
148                X509V3_conf_err(val);
149                goto err;
150            }
151            OPENSSL_free(tmp_data2);
152        } else if (strncmp(val->value, "file:", 5) == 0) {
153            unsigned char buf[2048];
154            int n;
155            BIO *b = BIO_new_file(val->value + 5, "r");
156            if (!b) {
157                X509V3err(X509V3_F_PROCESS_PCI_VALUE, ERR_R_BIO_LIB);
158                X509V3_conf_err(val);
159                goto err;
160            }
161            while ((n = BIO_read(b, buf, sizeof(buf))) > 0
162                   || (n == 0 && BIO_should_retry(b))) {
163                if (!n)
164                    continue;
165
166                tmp_data = OPENSSL_realloc((*policy)->data,
167                                           (*policy)->length + n + 1);
168
169                if (!tmp_data)
170                    break;
171
172                (*policy)->data = tmp_data;
173                memcpy(&(*policy)->data[(*policy)->length], buf, n);
174                (*policy)->length += n;
175                (*policy)->data[(*policy)->length] = '\0';
176            }
177            BIO_free_all(b);
178
179            if (n < 0) {
180                X509V3err(X509V3_F_PROCESS_PCI_VALUE, ERR_R_BIO_LIB);
181                X509V3_conf_err(val);
182                goto err;
183            }
184        } else if (strncmp(val->value, "text:", 5) == 0) {
185            val_len = strlen(val->value + 5);
186            tmp_data = OPENSSL_realloc((*policy)->data,
187                                       (*policy)->length + val_len + 1);
188            if (tmp_data) {
189                (*policy)->data = tmp_data;
190                memcpy(&(*policy)->data[(*policy)->length],
191                       val->value + 5, val_len);
192                (*policy)->length += val_len;
193                (*policy)->data[(*policy)->length] = '\0';
194            } else {
195                /*
196                 * realloc failure implies the original data space is b0rked
197                 * too!
198                 */
199                (*policy)->data = NULL;
200                (*policy)->length = 0;
201                X509V3err(X509V3_F_PROCESS_PCI_VALUE, ERR_R_MALLOC_FAILURE);
202                X509V3_conf_err(val);
203                goto err;
204            }
205        } else {
206            X509V3err(X509V3_F_PROCESS_PCI_VALUE,
207                      X509V3_R_INCORRECT_POLICY_SYNTAX_TAG);
208            X509V3_conf_err(val);
209            goto err;
210        }
211        if (!tmp_data) {
212            X509V3err(X509V3_F_PROCESS_PCI_VALUE, ERR_R_MALLOC_FAILURE);
213            X509V3_conf_err(val);
214            goto err;
215        }
216    }
217    return 1;
218 err:
219    if (free_policy) {
220        ASN1_OCTET_STRING_free(*policy);
221        *policy = NULL;
222    }
223    return 0;
224}
225
226static PROXY_CERT_INFO_EXTENSION *r2i_pci(X509V3_EXT_METHOD *method,
227                                          X509V3_CTX *ctx, char *value)
228{
229    PROXY_CERT_INFO_EXTENSION *pci = NULL;
230    STACK_OF(CONF_VALUE) *vals;
231    ASN1_OBJECT *language = NULL;
232    ASN1_INTEGER *pathlen = NULL;
233    ASN1_OCTET_STRING *policy = NULL;
234    int i, j;
235
236    vals = X509V3_parse_list(value);
237    for (i = 0; i < sk_CONF_VALUE_num(vals); i++) {
238        CONF_VALUE *cnf = sk_CONF_VALUE_value(vals, i);
239        if (!cnf->name || (*cnf->name != '@' && !cnf->value)) {
240            X509V3err(X509V3_F_R2I_PCI,
241                      X509V3_R_INVALID_PROXY_POLICY_SETTING);
242            X509V3_conf_err(cnf);
243            goto err;
244        }
245        if (*cnf->name == '@') {
246            STACK_OF(CONF_VALUE) *sect;
247            int success_p = 1;
248
249            sect = X509V3_get_section(ctx, cnf->name + 1);
250            if (!sect) {
251                X509V3err(X509V3_F_R2I_PCI, X509V3_R_INVALID_SECTION);
252                X509V3_conf_err(cnf);
253                goto err;
254            }
255            for (j = 0; success_p && j < sk_CONF_VALUE_num(sect); j++) {
256                success_p =
257                    process_pci_value(sk_CONF_VALUE_value(sect, j),
258                                      &language, &pathlen, &policy);
259            }
260            X509V3_section_free(ctx, sect);
261            if (!success_p)
262                goto err;
263        } else {
264            if (!process_pci_value(cnf, &language, &pathlen, &policy)) {
265                X509V3_conf_err(cnf);
266                goto err;
267            }
268        }
269    }
270
271    /* Language is mandatory */
272    if (!language) {
273        X509V3err(X509V3_F_R2I_PCI,
274                  X509V3_R_NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED);
275        goto err;
276    }
277    i = OBJ_obj2nid(language);
278    if ((i == NID_Independent || i == NID_id_ppl_inheritAll) && policy) {
279        X509V3err(X509V3_F_R2I_PCI,
280                  X509V3_R_POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY);
281        goto err;
282    }
283
284    pci = PROXY_CERT_INFO_EXTENSION_new();
285    if (!pci) {
286        X509V3err(X509V3_F_R2I_PCI, ERR_R_MALLOC_FAILURE);
287        goto err;
288    }
289
290    pci->proxyPolicy->policyLanguage = language;
291    language = NULL;
292    pci->proxyPolicy->policy = policy;
293    policy = NULL;
294    pci->pcPathLengthConstraint = pathlen;
295    pathlen = NULL;
296    goto end;
297 err:
298    if (language) {
299        ASN1_OBJECT_free(language);
300        language = NULL;
301    }
302    if (pathlen) {
303        ASN1_INTEGER_free(pathlen);
304        pathlen = NULL;
305    }
306    if (policy) {
307        ASN1_OCTET_STRING_free(policy);
308        policy = NULL;
309    }
310    if (pci) {
311        PROXY_CERT_INFO_EXTENSION_free(pci);
312        pci = NULL;
313    }
314 end:
315    sk_CONF_VALUE_pop_free(vals, X509V3_conf_free);
316    return pci;
317}
318