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