1*0Sstevel@tonic-gate /* v3_utl.c */ 2*0Sstevel@tonic-gate /* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL 3*0Sstevel@tonic-gate * project 1999. 4*0Sstevel@tonic-gate */ 5*0Sstevel@tonic-gate /* ==================================================================== 6*0Sstevel@tonic-gate * Copyright (c) 1999 The OpenSSL Project. All rights reserved. 7*0Sstevel@tonic-gate * 8*0Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 9*0Sstevel@tonic-gate * modification, are permitted provided that the following conditions 10*0Sstevel@tonic-gate * are met: 11*0Sstevel@tonic-gate * 12*0Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 13*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 14*0Sstevel@tonic-gate * 15*0Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 16*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in 17*0Sstevel@tonic-gate * the documentation and/or other materials provided with the 18*0Sstevel@tonic-gate * distribution. 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * 3. All advertising materials mentioning features or use of this 21*0Sstevel@tonic-gate * software must display the following acknowledgment: 22*0Sstevel@tonic-gate * "This product includes software developed by the OpenSSL Project 23*0Sstevel@tonic-gate * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 24*0Sstevel@tonic-gate * 25*0Sstevel@tonic-gate * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 26*0Sstevel@tonic-gate * endorse or promote products derived from this software without 27*0Sstevel@tonic-gate * prior written permission. For written permission, please contact 28*0Sstevel@tonic-gate * licensing@OpenSSL.org. 29*0Sstevel@tonic-gate * 30*0Sstevel@tonic-gate * 5. Products derived from this software may not be called "OpenSSL" 31*0Sstevel@tonic-gate * nor may "OpenSSL" appear in their names without prior written 32*0Sstevel@tonic-gate * permission of the OpenSSL Project. 33*0Sstevel@tonic-gate * 34*0Sstevel@tonic-gate * 6. Redistributions of any form whatsoever must retain the following 35*0Sstevel@tonic-gate * acknowledgment: 36*0Sstevel@tonic-gate * "This product includes software developed by the OpenSSL Project 37*0Sstevel@tonic-gate * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 38*0Sstevel@tonic-gate * 39*0Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 40*0Sstevel@tonic-gate * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 41*0Sstevel@tonic-gate * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 42*0Sstevel@tonic-gate * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 43*0Sstevel@tonic-gate * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 44*0Sstevel@tonic-gate * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 45*0Sstevel@tonic-gate * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 46*0Sstevel@tonic-gate * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 47*0Sstevel@tonic-gate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 48*0Sstevel@tonic-gate * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 49*0Sstevel@tonic-gate * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 50*0Sstevel@tonic-gate * OF THE POSSIBILITY OF SUCH DAMAGE. 51*0Sstevel@tonic-gate * ==================================================================== 52*0Sstevel@tonic-gate * 53*0Sstevel@tonic-gate * This product includes cryptographic software written by Eric Young 54*0Sstevel@tonic-gate * (eay@cryptsoft.com). This product includes software written by Tim 55*0Sstevel@tonic-gate * Hudson (tjh@cryptsoft.com). 56*0Sstevel@tonic-gate * 57*0Sstevel@tonic-gate */ 58*0Sstevel@tonic-gate /* X509 v3 extension utilities */ 59*0Sstevel@tonic-gate 60*0Sstevel@tonic-gate 61*0Sstevel@tonic-gate #include <stdio.h> 62*0Sstevel@tonic-gate #include <ctype.h> 63*0Sstevel@tonic-gate #include "cryptlib.h" 64*0Sstevel@tonic-gate #include <openssl/conf.h> 65*0Sstevel@tonic-gate #include <openssl/x509v3.h> 66*0Sstevel@tonic-gate 67*0Sstevel@tonic-gate static char *strip_spaces(char *name); 68*0Sstevel@tonic-gate static int sk_strcmp(const char * const *a, const char * const *b); 69*0Sstevel@tonic-gate static STACK *get_email(X509_NAME *name, GENERAL_NAMES *gens); 70*0Sstevel@tonic-gate static void str_free(void *str); 71*0Sstevel@tonic-gate static int append_ia5(STACK **sk, ASN1_IA5STRING *email); 72*0Sstevel@tonic-gate 73*0Sstevel@tonic-gate /* Add a CONF_VALUE name value pair to stack */ 74*0Sstevel@tonic-gate 75*0Sstevel@tonic-gate int X509V3_add_value(const char *name, const char *value, 76*0Sstevel@tonic-gate STACK_OF(CONF_VALUE) **extlist) 77*0Sstevel@tonic-gate { 78*0Sstevel@tonic-gate CONF_VALUE *vtmp = NULL; 79*0Sstevel@tonic-gate char *tname = NULL, *tvalue = NULL; 80*0Sstevel@tonic-gate if(name && !(tname = BUF_strdup(name))) goto err; 81*0Sstevel@tonic-gate if(value && !(tvalue = BUF_strdup(value))) goto err;; 82*0Sstevel@tonic-gate if(!(vtmp = (CONF_VALUE *)OPENSSL_malloc(sizeof(CONF_VALUE)))) goto err; 83*0Sstevel@tonic-gate if(!*extlist && !(*extlist = sk_CONF_VALUE_new_null())) goto err; 84*0Sstevel@tonic-gate vtmp->section = NULL; 85*0Sstevel@tonic-gate vtmp->name = tname; 86*0Sstevel@tonic-gate vtmp->value = tvalue; 87*0Sstevel@tonic-gate if(!sk_CONF_VALUE_push(*extlist, vtmp)) goto err; 88*0Sstevel@tonic-gate return 1; 89*0Sstevel@tonic-gate err: 90*0Sstevel@tonic-gate X509V3err(X509V3_F_X509V3_ADD_VALUE,ERR_R_MALLOC_FAILURE); 91*0Sstevel@tonic-gate if(vtmp) OPENSSL_free(vtmp); 92*0Sstevel@tonic-gate if(tname) OPENSSL_free(tname); 93*0Sstevel@tonic-gate if(tvalue) OPENSSL_free(tvalue); 94*0Sstevel@tonic-gate return 0; 95*0Sstevel@tonic-gate } 96*0Sstevel@tonic-gate 97*0Sstevel@tonic-gate int X509V3_add_value_uchar(const char *name, const unsigned char *value, 98*0Sstevel@tonic-gate STACK_OF(CONF_VALUE) **extlist) 99*0Sstevel@tonic-gate { 100*0Sstevel@tonic-gate return X509V3_add_value(name,(const char *)value,extlist); 101*0Sstevel@tonic-gate } 102*0Sstevel@tonic-gate 103*0Sstevel@tonic-gate /* Free function for STACK_OF(CONF_VALUE) */ 104*0Sstevel@tonic-gate 105*0Sstevel@tonic-gate void X509V3_conf_free(CONF_VALUE *conf) 106*0Sstevel@tonic-gate { 107*0Sstevel@tonic-gate if(!conf) return; 108*0Sstevel@tonic-gate if(conf->name) OPENSSL_free(conf->name); 109*0Sstevel@tonic-gate if(conf->value) OPENSSL_free(conf->value); 110*0Sstevel@tonic-gate if(conf->section) OPENSSL_free(conf->section); 111*0Sstevel@tonic-gate OPENSSL_free(conf); 112*0Sstevel@tonic-gate } 113*0Sstevel@tonic-gate 114*0Sstevel@tonic-gate int X509V3_add_value_bool(const char *name, int asn1_bool, 115*0Sstevel@tonic-gate STACK_OF(CONF_VALUE) **extlist) 116*0Sstevel@tonic-gate { 117*0Sstevel@tonic-gate if(asn1_bool) return X509V3_add_value(name, "TRUE", extlist); 118*0Sstevel@tonic-gate return X509V3_add_value(name, "FALSE", extlist); 119*0Sstevel@tonic-gate } 120*0Sstevel@tonic-gate 121*0Sstevel@tonic-gate int X509V3_add_value_bool_nf(char *name, int asn1_bool, 122*0Sstevel@tonic-gate STACK_OF(CONF_VALUE) **extlist) 123*0Sstevel@tonic-gate { 124*0Sstevel@tonic-gate if(asn1_bool) return X509V3_add_value(name, "TRUE", extlist); 125*0Sstevel@tonic-gate return 1; 126*0Sstevel@tonic-gate } 127*0Sstevel@tonic-gate 128*0Sstevel@tonic-gate 129*0Sstevel@tonic-gate char *i2s_ASN1_ENUMERATED(X509V3_EXT_METHOD *method, ASN1_ENUMERATED *a) 130*0Sstevel@tonic-gate { 131*0Sstevel@tonic-gate BIGNUM *bntmp = NULL; 132*0Sstevel@tonic-gate char *strtmp = NULL; 133*0Sstevel@tonic-gate if(!a) return NULL; 134*0Sstevel@tonic-gate if(!(bntmp = ASN1_ENUMERATED_to_BN(a, NULL)) || 135*0Sstevel@tonic-gate !(strtmp = BN_bn2dec(bntmp)) ) 136*0Sstevel@tonic-gate X509V3err(X509V3_F_I2S_ASN1_ENUMERATED,ERR_R_MALLOC_FAILURE); 137*0Sstevel@tonic-gate BN_free(bntmp); 138*0Sstevel@tonic-gate return strtmp; 139*0Sstevel@tonic-gate } 140*0Sstevel@tonic-gate 141*0Sstevel@tonic-gate char *i2s_ASN1_INTEGER(X509V3_EXT_METHOD *method, ASN1_INTEGER *a) 142*0Sstevel@tonic-gate { 143*0Sstevel@tonic-gate BIGNUM *bntmp = NULL; 144*0Sstevel@tonic-gate char *strtmp = NULL; 145*0Sstevel@tonic-gate if(!a) return NULL; 146*0Sstevel@tonic-gate if(!(bntmp = ASN1_INTEGER_to_BN(a, NULL)) || 147*0Sstevel@tonic-gate !(strtmp = BN_bn2dec(bntmp)) ) 148*0Sstevel@tonic-gate X509V3err(X509V3_F_I2S_ASN1_INTEGER,ERR_R_MALLOC_FAILURE); 149*0Sstevel@tonic-gate BN_free(bntmp); 150*0Sstevel@tonic-gate return strtmp; 151*0Sstevel@tonic-gate } 152*0Sstevel@tonic-gate 153*0Sstevel@tonic-gate ASN1_INTEGER *s2i_ASN1_INTEGER(X509V3_EXT_METHOD *method, char *value) 154*0Sstevel@tonic-gate { 155*0Sstevel@tonic-gate BIGNUM *bn = NULL; 156*0Sstevel@tonic-gate ASN1_INTEGER *aint; 157*0Sstevel@tonic-gate int isneg, ishex; 158*0Sstevel@tonic-gate int ret; 159*0Sstevel@tonic-gate bn = BN_new(); 160*0Sstevel@tonic-gate if (!value) { 161*0Sstevel@tonic-gate X509V3err(X509V3_F_S2I_ASN1_INTEGER,X509V3_R_INVALID_NULL_VALUE); 162*0Sstevel@tonic-gate return 0; 163*0Sstevel@tonic-gate } 164*0Sstevel@tonic-gate if (value[0] == '-') { 165*0Sstevel@tonic-gate value++; 166*0Sstevel@tonic-gate isneg = 1; 167*0Sstevel@tonic-gate } else isneg = 0; 168*0Sstevel@tonic-gate 169*0Sstevel@tonic-gate if (value[0] == '0' && ((value[1] == 'x') || (value[1] == 'X'))) { 170*0Sstevel@tonic-gate value += 2; 171*0Sstevel@tonic-gate ishex = 1; 172*0Sstevel@tonic-gate } else ishex = 0; 173*0Sstevel@tonic-gate 174*0Sstevel@tonic-gate if (ishex) ret = BN_hex2bn(&bn, value); 175*0Sstevel@tonic-gate else ret = BN_dec2bn(&bn, value); 176*0Sstevel@tonic-gate 177*0Sstevel@tonic-gate if (!ret) { 178*0Sstevel@tonic-gate X509V3err(X509V3_F_S2I_ASN1_INTEGER,X509V3_R_BN_DEC2BN_ERROR); 179*0Sstevel@tonic-gate return 0; 180*0Sstevel@tonic-gate } 181*0Sstevel@tonic-gate 182*0Sstevel@tonic-gate if (isneg && BN_is_zero(bn)) isneg = 0; 183*0Sstevel@tonic-gate 184*0Sstevel@tonic-gate aint = BN_to_ASN1_INTEGER(bn, NULL); 185*0Sstevel@tonic-gate BN_free(bn); 186*0Sstevel@tonic-gate if (!aint) { 187*0Sstevel@tonic-gate X509V3err(X509V3_F_S2I_ASN1_INTEGER,X509V3_R_BN_TO_ASN1_INTEGER_ERROR); 188*0Sstevel@tonic-gate return 0; 189*0Sstevel@tonic-gate } 190*0Sstevel@tonic-gate if (isneg) aint->type |= V_ASN1_NEG; 191*0Sstevel@tonic-gate return aint; 192*0Sstevel@tonic-gate } 193*0Sstevel@tonic-gate 194*0Sstevel@tonic-gate int X509V3_add_value_int(const char *name, ASN1_INTEGER *aint, 195*0Sstevel@tonic-gate STACK_OF(CONF_VALUE) **extlist) 196*0Sstevel@tonic-gate { 197*0Sstevel@tonic-gate char *strtmp; 198*0Sstevel@tonic-gate int ret; 199*0Sstevel@tonic-gate if(!aint) return 1; 200*0Sstevel@tonic-gate if(!(strtmp = i2s_ASN1_INTEGER(NULL, aint))) return 0; 201*0Sstevel@tonic-gate ret = X509V3_add_value(name, strtmp, extlist); 202*0Sstevel@tonic-gate OPENSSL_free(strtmp); 203*0Sstevel@tonic-gate return ret; 204*0Sstevel@tonic-gate } 205*0Sstevel@tonic-gate 206*0Sstevel@tonic-gate int X509V3_get_value_bool(CONF_VALUE *value, int *asn1_bool) 207*0Sstevel@tonic-gate { 208*0Sstevel@tonic-gate char *btmp; 209*0Sstevel@tonic-gate if(!(btmp = value->value)) goto err; 210*0Sstevel@tonic-gate if(!strcmp(btmp, "TRUE") || !strcmp(btmp, "true") 211*0Sstevel@tonic-gate || !strcmp(btmp, "Y") || !strcmp(btmp, "y") 212*0Sstevel@tonic-gate || !strcmp(btmp, "YES") || !strcmp(btmp, "yes")) { 213*0Sstevel@tonic-gate *asn1_bool = 0xff; 214*0Sstevel@tonic-gate return 1; 215*0Sstevel@tonic-gate } else if(!strcmp(btmp, "FALSE") || !strcmp(btmp, "false") 216*0Sstevel@tonic-gate || !strcmp(btmp, "N") || !strcmp(btmp, "n") 217*0Sstevel@tonic-gate || !strcmp(btmp, "NO") || !strcmp(btmp, "no")) { 218*0Sstevel@tonic-gate *asn1_bool = 0; 219*0Sstevel@tonic-gate return 1; 220*0Sstevel@tonic-gate } 221*0Sstevel@tonic-gate err: 222*0Sstevel@tonic-gate X509V3err(X509V3_F_X509V3_GET_VALUE_BOOL,X509V3_R_INVALID_BOOLEAN_STRING); 223*0Sstevel@tonic-gate X509V3_conf_err(value); 224*0Sstevel@tonic-gate return 0; 225*0Sstevel@tonic-gate } 226*0Sstevel@tonic-gate 227*0Sstevel@tonic-gate int X509V3_get_value_int(CONF_VALUE *value, ASN1_INTEGER **aint) 228*0Sstevel@tonic-gate { 229*0Sstevel@tonic-gate ASN1_INTEGER *itmp; 230*0Sstevel@tonic-gate if(!(itmp = s2i_ASN1_INTEGER(NULL, value->value))) { 231*0Sstevel@tonic-gate X509V3_conf_err(value); 232*0Sstevel@tonic-gate return 0; 233*0Sstevel@tonic-gate } 234*0Sstevel@tonic-gate *aint = itmp; 235*0Sstevel@tonic-gate return 1; 236*0Sstevel@tonic-gate } 237*0Sstevel@tonic-gate 238*0Sstevel@tonic-gate #define HDR_NAME 1 239*0Sstevel@tonic-gate #define HDR_VALUE 2 240*0Sstevel@tonic-gate 241*0Sstevel@tonic-gate /*#define DEBUG*/ 242*0Sstevel@tonic-gate 243*0Sstevel@tonic-gate STACK_OF(CONF_VALUE) *X509V3_parse_list(const char *line) 244*0Sstevel@tonic-gate { 245*0Sstevel@tonic-gate char *p, *q, c; 246*0Sstevel@tonic-gate char *ntmp, *vtmp; 247*0Sstevel@tonic-gate STACK_OF(CONF_VALUE) *values = NULL; 248*0Sstevel@tonic-gate char *linebuf; 249*0Sstevel@tonic-gate int state; 250*0Sstevel@tonic-gate /* We are going to modify the line so copy it first */ 251*0Sstevel@tonic-gate linebuf = BUF_strdup(line); 252*0Sstevel@tonic-gate state = HDR_NAME; 253*0Sstevel@tonic-gate ntmp = NULL; 254*0Sstevel@tonic-gate /* Go through all characters */ 255*0Sstevel@tonic-gate for(p = linebuf, q = linebuf; (c = *p) && (c!='\r') && (c!='\n'); p++) { 256*0Sstevel@tonic-gate 257*0Sstevel@tonic-gate switch(state) { 258*0Sstevel@tonic-gate case HDR_NAME: 259*0Sstevel@tonic-gate if(c == ':') { 260*0Sstevel@tonic-gate state = HDR_VALUE; 261*0Sstevel@tonic-gate *p = 0; 262*0Sstevel@tonic-gate ntmp = strip_spaces(q); 263*0Sstevel@tonic-gate if(!ntmp) { 264*0Sstevel@tonic-gate X509V3err(X509V3_F_X509V3_PARSE_LIST, X509V3_R_INVALID_NULL_NAME); 265*0Sstevel@tonic-gate goto err; 266*0Sstevel@tonic-gate } 267*0Sstevel@tonic-gate q = p + 1; 268*0Sstevel@tonic-gate } else if(c == ',') { 269*0Sstevel@tonic-gate *p = 0; 270*0Sstevel@tonic-gate ntmp = strip_spaces(q); 271*0Sstevel@tonic-gate q = p + 1; 272*0Sstevel@tonic-gate #if 0 273*0Sstevel@tonic-gate printf("%s\n", ntmp); 274*0Sstevel@tonic-gate #endif 275*0Sstevel@tonic-gate if(!ntmp) { 276*0Sstevel@tonic-gate X509V3err(X509V3_F_X509V3_PARSE_LIST, X509V3_R_INVALID_NULL_NAME); 277*0Sstevel@tonic-gate goto err; 278*0Sstevel@tonic-gate } 279*0Sstevel@tonic-gate X509V3_add_value(ntmp, NULL, &values); 280*0Sstevel@tonic-gate } 281*0Sstevel@tonic-gate break ; 282*0Sstevel@tonic-gate 283*0Sstevel@tonic-gate case HDR_VALUE: 284*0Sstevel@tonic-gate if(c == ',') { 285*0Sstevel@tonic-gate state = HDR_NAME; 286*0Sstevel@tonic-gate *p = 0; 287*0Sstevel@tonic-gate vtmp = strip_spaces(q); 288*0Sstevel@tonic-gate #if 0 289*0Sstevel@tonic-gate printf("%s\n", ntmp); 290*0Sstevel@tonic-gate #endif 291*0Sstevel@tonic-gate if(!vtmp) { 292*0Sstevel@tonic-gate X509V3err(X509V3_F_X509V3_PARSE_LIST, X509V3_R_INVALID_NULL_VALUE); 293*0Sstevel@tonic-gate goto err; 294*0Sstevel@tonic-gate } 295*0Sstevel@tonic-gate X509V3_add_value(ntmp, vtmp, &values); 296*0Sstevel@tonic-gate ntmp = NULL; 297*0Sstevel@tonic-gate q = p + 1; 298*0Sstevel@tonic-gate } 299*0Sstevel@tonic-gate 300*0Sstevel@tonic-gate } 301*0Sstevel@tonic-gate } 302*0Sstevel@tonic-gate 303*0Sstevel@tonic-gate if(state == HDR_VALUE) { 304*0Sstevel@tonic-gate vtmp = strip_spaces(q); 305*0Sstevel@tonic-gate #if 0 306*0Sstevel@tonic-gate printf("%s=%s\n", ntmp, vtmp); 307*0Sstevel@tonic-gate #endif 308*0Sstevel@tonic-gate if(!vtmp) { 309*0Sstevel@tonic-gate X509V3err(X509V3_F_X509V3_PARSE_LIST, X509V3_R_INVALID_NULL_VALUE); 310*0Sstevel@tonic-gate goto err; 311*0Sstevel@tonic-gate } 312*0Sstevel@tonic-gate X509V3_add_value(ntmp, vtmp, &values); 313*0Sstevel@tonic-gate } else { 314*0Sstevel@tonic-gate ntmp = strip_spaces(q); 315*0Sstevel@tonic-gate #if 0 316*0Sstevel@tonic-gate printf("%s\n", ntmp); 317*0Sstevel@tonic-gate #endif 318*0Sstevel@tonic-gate if(!ntmp) { 319*0Sstevel@tonic-gate X509V3err(X509V3_F_X509V3_PARSE_LIST, X509V3_R_INVALID_NULL_NAME); 320*0Sstevel@tonic-gate goto err; 321*0Sstevel@tonic-gate } 322*0Sstevel@tonic-gate X509V3_add_value(ntmp, NULL, &values); 323*0Sstevel@tonic-gate } 324*0Sstevel@tonic-gate OPENSSL_free(linebuf); 325*0Sstevel@tonic-gate return values; 326*0Sstevel@tonic-gate 327*0Sstevel@tonic-gate err: 328*0Sstevel@tonic-gate OPENSSL_free(linebuf); 329*0Sstevel@tonic-gate sk_CONF_VALUE_pop_free(values, X509V3_conf_free); 330*0Sstevel@tonic-gate return NULL; 331*0Sstevel@tonic-gate 332*0Sstevel@tonic-gate } 333*0Sstevel@tonic-gate 334*0Sstevel@tonic-gate /* Delete leading and trailing spaces from a string */ 335*0Sstevel@tonic-gate static char *strip_spaces(char *name) 336*0Sstevel@tonic-gate { 337*0Sstevel@tonic-gate char *p, *q; 338*0Sstevel@tonic-gate /* Skip over leading spaces */ 339*0Sstevel@tonic-gate p = name; 340*0Sstevel@tonic-gate while(*p && isspace((unsigned char)*p)) p++; 341*0Sstevel@tonic-gate if(!*p) return NULL; 342*0Sstevel@tonic-gate q = p + strlen(p) - 1; 343*0Sstevel@tonic-gate while((q != p) && isspace((unsigned char)*q)) q--; 344*0Sstevel@tonic-gate if(p != q) q[1] = 0; 345*0Sstevel@tonic-gate if(!*p) return NULL; 346*0Sstevel@tonic-gate return p; 347*0Sstevel@tonic-gate } 348*0Sstevel@tonic-gate 349*0Sstevel@tonic-gate /* hex string utilities */ 350*0Sstevel@tonic-gate 351*0Sstevel@tonic-gate /* Given a buffer of length 'len' return a OPENSSL_malloc'ed string with its 352*0Sstevel@tonic-gate * hex representation 353*0Sstevel@tonic-gate * @@@ (Contents of buffer are always kept in ASCII, also on EBCDIC machines) 354*0Sstevel@tonic-gate */ 355*0Sstevel@tonic-gate 356*0Sstevel@tonic-gate char *hex_to_string(unsigned char *buffer, long len) 357*0Sstevel@tonic-gate { 358*0Sstevel@tonic-gate char *tmp, *q; 359*0Sstevel@tonic-gate unsigned char *p; 360*0Sstevel@tonic-gate int i; 361*0Sstevel@tonic-gate static char hexdig[] = "0123456789ABCDEF"; 362*0Sstevel@tonic-gate if(!buffer || !len) return NULL; 363*0Sstevel@tonic-gate if(!(tmp = OPENSSL_malloc(len * 3 + 1))) { 364*0Sstevel@tonic-gate X509V3err(X509V3_F_HEX_TO_STRING,ERR_R_MALLOC_FAILURE); 365*0Sstevel@tonic-gate return NULL; 366*0Sstevel@tonic-gate } 367*0Sstevel@tonic-gate q = tmp; 368*0Sstevel@tonic-gate for(i = 0, p = buffer; i < len; i++,p++) { 369*0Sstevel@tonic-gate *q++ = hexdig[(*p >> 4) & 0xf]; 370*0Sstevel@tonic-gate *q++ = hexdig[*p & 0xf]; 371*0Sstevel@tonic-gate *q++ = ':'; 372*0Sstevel@tonic-gate } 373*0Sstevel@tonic-gate q[-1] = 0; 374*0Sstevel@tonic-gate #ifdef CHARSET_EBCDIC 375*0Sstevel@tonic-gate ebcdic2ascii(tmp, tmp, q - tmp - 1); 376*0Sstevel@tonic-gate #endif 377*0Sstevel@tonic-gate 378*0Sstevel@tonic-gate return tmp; 379*0Sstevel@tonic-gate } 380*0Sstevel@tonic-gate 381*0Sstevel@tonic-gate /* Give a string of hex digits convert to 382*0Sstevel@tonic-gate * a buffer 383*0Sstevel@tonic-gate */ 384*0Sstevel@tonic-gate 385*0Sstevel@tonic-gate unsigned char *string_to_hex(char *str, long *len) 386*0Sstevel@tonic-gate { 387*0Sstevel@tonic-gate unsigned char *hexbuf, *q; 388*0Sstevel@tonic-gate unsigned char ch, cl, *p; 389*0Sstevel@tonic-gate if(!str) { 390*0Sstevel@tonic-gate X509V3err(X509V3_F_STRING_TO_HEX,X509V3_R_INVALID_NULL_ARGUMENT); 391*0Sstevel@tonic-gate return NULL; 392*0Sstevel@tonic-gate } 393*0Sstevel@tonic-gate if(!(hexbuf = OPENSSL_malloc(strlen(str) >> 1))) goto err; 394*0Sstevel@tonic-gate for(p = (unsigned char *)str, q = hexbuf; *p;) { 395*0Sstevel@tonic-gate ch = *p++; 396*0Sstevel@tonic-gate #ifdef CHARSET_EBCDIC 397*0Sstevel@tonic-gate ch = os_toebcdic[ch]; 398*0Sstevel@tonic-gate #endif 399*0Sstevel@tonic-gate if(ch == ':') continue; 400*0Sstevel@tonic-gate cl = *p++; 401*0Sstevel@tonic-gate #ifdef CHARSET_EBCDIC 402*0Sstevel@tonic-gate cl = os_toebcdic[cl]; 403*0Sstevel@tonic-gate #endif 404*0Sstevel@tonic-gate if(!cl) { 405*0Sstevel@tonic-gate X509V3err(X509V3_F_STRING_TO_HEX,X509V3_R_ODD_NUMBER_OF_DIGITS); 406*0Sstevel@tonic-gate OPENSSL_free(hexbuf); 407*0Sstevel@tonic-gate return NULL; 408*0Sstevel@tonic-gate } 409*0Sstevel@tonic-gate if(isupper(ch)) ch = tolower(ch); 410*0Sstevel@tonic-gate if(isupper(cl)) cl = tolower(cl); 411*0Sstevel@tonic-gate 412*0Sstevel@tonic-gate if((ch >= '0') && (ch <= '9')) ch -= '0'; 413*0Sstevel@tonic-gate else if ((ch >= 'a') && (ch <= 'f')) ch -= 'a' - 10; 414*0Sstevel@tonic-gate else goto badhex; 415*0Sstevel@tonic-gate 416*0Sstevel@tonic-gate if((cl >= '0') && (cl <= '9')) cl -= '0'; 417*0Sstevel@tonic-gate else if ((cl >= 'a') && (cl <= 'f')) cl -= 'a' - 10; 418*0Sstevel@tonic-gate else goto badhex; 419*0Sstevel@tonic-gate 420*0Sstevel@tonic-gate *q++ = (ch << 4) | cl; 421*0Sstevel@tonic-gate } 422*0Sstevel@tonic-gate 423*0Sstevel@tonic-gate if(len) *len = q - hexbuf; 424*0Sstevel@tonic-gate 425*0Sstevel@tonic-gate return hexbuf; 426*0Sstevel@tonic-gate 427*0Sstevel@tonic-gate err: 428*0Sstevel@tonic-gate if(hexbuf) OPENSSL_free(hexbuf); 429*0Sstevel@tonic-gate X509V3err(X509V3_F_STRING_TO_HEX,ERR_R_MALLOC_FAILURE); 430*0Sstevel@tonic-gate return NULL; 431*0Sstevel@tonic-gate 432*0Sstevel@tonic-gate badhex: 433*0Sstevel@tonic-gate OPENSSL_free(hexbuf); 434*0Sstevel@tonic-gate X509V3err(X509V3_F_STRING_TO_HEX,X509V3_R_ILLEGAL_HEX_DIGIT); 435*0Sstevel@tonic-gate return NULL; 436*0Sstevel@tonic-gate 437*0Sstevel@tonic-gate } 438*0Sstevel@tonic-gate 439*0Sstevel@tonic-gate /* V2I name comparison function: returns zero if 'name' matches 440*0Sstevel@tonic-gate * cmp or cmp.* 441*0Sstevel@tonic-gate */ 442*0Sstevel@tonic-gate 443*0Sstevel@tonic-gate int name_cmp(const char *name, const char *cmp) 444*0Sstevel@tonic-gate { 445*0Sstevel@tonic-gate int len, ret; 446*0Sstevel@tonic-gate char c; 447*0Sstevel@tonic-gate len = strlen(cmp); 448*0Sstevel@tonic-gate if((ret = strncmp(name, cmp, len))) return ret; 449*0Sstevel@tonic-gate c = name[len]; 450*0Sstevel@tonic-gate if(!c || (c=='.')) return 0; 451*0Sstevel@tonic-gate return 1; 452*0Sstevel@tonic-gate } 453*0Sstevel@tonic-gate 454*0Sstevel@tonic-gate static int sk_strcmp(const char * const *a, const char * const *b) 455*0Sstevel@tonic-gate { 456*0Sstevel@tonic-gate return strcmp(*a, *b); 457*0Sstevel@tonic-gate } 458*0Sstevel@tonic-gate 459*0Sstevel@tonic-gate STACK *X509_get1_email(X509 *x) 460*0Sstevel@tonic-gate { 461*0Sstevel@tonic-gate GENERAL_NAMES *gens; 462*0Sstevel@tonic-gate STACK *ret; 463*0Sstevel@tonic-gate gens = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL); 464*0Sstevel@tonic-gate ret = get_email(X509_get_subject_name(x), gens); 465*0Sstevel@tonic-gate sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free); 466*0Sstevel@tonic-gate return ret; 467*0Sstevel@tonic-gate } 468*0Sstevel@tonic-gate 469*0Sstevel@tonic-gate STACK *X509_REQ_get1_email(X509_REQ *x) 470*0Sstevel@tonic-gate { 471*0Sstevel@tonic-gate GENERAL_NAMES *gens; 472*0Sstevel@tonic-gate STACK_OF(X509_EXTENSION) *exts; 473*0Sstevel@tonic-gate STACK *ret; 474*0Sstevel@tonic-gate exts = X509_REQ_get_extensions(x); 475*0Sstevel@tonic-gate gens = X509V3_get_d2i(exts, NID_subject_alt_name, NULL, NULL); 476*0Sstevel@tonic-gate ret = get_email(X509_REQ_get_subject_name(x), gens); 477*0Sstevel@tonic-gate sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free); 478*0Sstevel@tonic-gate sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); 479*0Sstevel@tonic-gate return ret; 480*0Sstevel@tonic-gate } 481*0Sstevel@tonic-gate 482*0Sstevel@tonic-gate 483*0Sstevel@tonic-gate static STACK *get_email(X509_NAME *name, GENERAL_NAMES *gens) 484*0Sstevel@tonic-gate { 485*0Sstevel@tonic-gate STACK *ret = NULL; 486*0Sstevel@tonic-gate X509_NAME_ENTRY *ne; 487*0Sstevel@tonic-gate ASN1_IA5STRING *email; 488*0Sstevel@tonic-gate GENERAL_NAME *gen; 489*0Sstevel@tonic-gate int i; 490*0Sstevel@tonic-gate /* Now add any email address(es) to STACK */ 491*0Sstevel@tonic-gate i = -1; 492*0Sstevel@tonic-gate /* First supplied X509_NAME */ 493*0Sstevel@tonic-gate while((i = X509_NAME_get_index_by_NID(name, 494*0Sstevel@tonic-gate NID_pkcs9_emailAddress, i)) >= 0) { 495*0Sstevel@tonic-gate ne = X509_NAME_get_entry(name, i); 496*0Sstevel@tonic-gate email = X509_NAME_ENTRY_get_data(ne); 497*0Sstevel@tonic-gate if(!append_ia5(&ret, email)) return NULL; 498*0Sstevel@tonic-gate } 499*0Sstevel@tonic-gate for(i = 0; i < sk_GENERAL_NAME_num(gens); i++) 500*0Sstevel@tonic-gate { 501*0Sstevel@tonic-gate gen = sk_GENERAL_NAME_value(gens, i); 502*0Sstevel@tonic-gate if(gen->type != GEN_EMAIL) continue; 503*0Sstevel@tonic-gate if(!append_ia5(&ret, gen->d.ia5)) return NULL; 504*0Sstevel@tonic-gate } 505*0Sstevel@tonic-gate return ret; 506*0Sstevel@tonic-gate } 507*0Sstevel@tonic-gate 508*0Sstevel@tonic-gate static void str_free(void *str) 509*0Sstevel@tonic-gate { 510*0Sstevel@tonic-gate OPENSSL_free(str); 511*0Sstevel@tonic-gate } 512*0Sstevel@tonic-gate 513*0Sstevel@tonic-gate static int append_ia5(STACK **sk, ASN1_IA5STRING *email) 514*0Sstevel@tonic-gate { 515*0Sstevel@tonic-gate char *emtmp; 516*0Sstevel@tonic-gate /* First some sanity checks */ 517*0Sstevel@tonic-gate if(email->type != V_ASN1_IA5STRING) return 1; 518*0Sstevel@tonic-gate if(!email->data || !email->length) return 1; 519*0Sstevel@tonic-gate if(!*sk) *sk = sk_new(sk_strcmp); 520*0Sstevel@tonic-gate if(!*sk) return 0; 521*0Sstevel@tonic-gate /* Don't add duplicates */ 522*0Sstevel@tonic-gate if(sk_find(*sk, (char *)email->data) != -1) return 1; 523*0Sstevel@tonic-gate emtmp = BUF_strdup((char *)email->data); 524*0Sstevel@tonic-gate if(!emtmp || !sk_push(*sk, emtmp)) { 525*0Sstevel@tonic-gate X509_email_free(*sk); 526*0Sstevel@tonic-gate *sk = NULL; 527*0Sstevel@tonic-gate return 0; 528*0Sstevel@tonic-gate } 529*0Sstevel@tonic-gate return 1; 530*0Sstevel@tonic-gate } 531*0Sstevel@tonic-gate 532*0Sstevel@tonic-gate void X509_email_free(STACK *sk) 533*0Sstevel@tonic-gate { 534*0Sstevel@tonic-gate sk_pop_free(sk, str_free); 535*0Sstevel@tonic-gate } 536