1 /* $OpenBSD: x509name.c,v 1.13 2014/09/29 04:17:24 miod Exp $ */ 2 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 3 * All rights reserved. 4 * 5 * This package is an SSL implementation written 6 * by Eric Young (eay@cryptsoft.com). 7 * The implementation was written so as to conform with Netscapes SSL. 8 * 9 * This library is free for commercial and non-commercial use as long as 10 * the following conditions are aheared to. The following conditions 11 * apply to all code found in this distribution, be it the RC4, RSA, 12 * lhash, DES, etc., code; not just the SSL code. The SSL documentation 13 * included with this distribution is covered by the same copyright terms 14 * except that the holder is Tim Hudson (tjh@cryptsoft.com). 15 * 16 * Copyright remains Eric Young's, and as such any Copyright notices in 17 * the code are not to be removed. 18 * If this package is used in a product, Eric Young should be given attribution 19 * as the author of the parts of the library used. 20 * This can be in the form of a textual message at program startup or 21 * in documentation (online or textual) provided with the package. 22 * 23 * Redistribution and use in source and binary forms, with or without 24 * modification, are permitted provided that the following conditions 25 * are met: 26 * 1. Redistributions of source code must retain the copyright 27 * notice, this list of conditions and the following disclaimer. 28 * 2. Redistributions in binary form must reproduce the above copyright 29 * notice, this list of conditions and the following disclaimer in the 30 * documentation and/or other materials provided with the distribution. 31 * 3. All advertising materials mentioning features or use of this software 32 * must display the following acknowledgement: 33 * "This product includes cryptographic software written by 34 * Eric Young (eay@cryptsoft.com)" 35 * The word 'cryptographic' can be left out if the rouines from the library 36 * being used are not cryptographic related :-). 37 * 4. If you include any Windows specific code (or a derivative thereof) from 38 * the apps directory (application code) you must include an acknowledgement: 39 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 40 * 41 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51 * SUCH DAMAGE. 52 * 53 * The licence and distribution terms for any publically available version or 54 * derivative of this code cannot be changed. i.e. this code cannot simply be 55 * copied and put under another distribution licence 56 * [including the GNU Public Licence.] 57 */ 58 59 #include <stdio.h> 60 #include <string.h> 61 62 #include <openssl/asn1.h> 63 #include <openssl/err.h> 64 #include <openssl/evp.h> 65 #include <openssl/objects.h> 66 #include <openssl/stack.h> 67 #include <openssl/x509.h> 68 69 int 70 X509_NAME_get_text_by_NID(X509_NAME *name, int nid, char *buf, int len) 71 { 72 ASN1_OBJECT *obj; 73 74 obj = OBJ_nid2obj(nid); 75 if (obj == NULL) 76 return (-1); 77 return (X509_NAME_get_text_by_OBJ(name, obj, buf, len)); 78 } 79 80 int 81 X509_NAME_get_text_by_OBJ(X509_NAME *name, ASN1_OBJECT *obj, char *buf, 82 int len) 83 { 84 int i; 85 ASN1_STRING *data; 86 87 i = X509_NAME_get_index_by_OBJ(name, obj, -1); 88 if (i < 0) 89 return (-1); 90 data = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, i)); 91 i = (data->length > (len - 1)) ? (len - 1) : data->length; 92 if (buf == NULL) 93 return (data->length); 94 if (i >= 0) { 95 memcpy(buf, data->data, i); 96 buf[i] = '\0'; 97 } 98 return (i); 99 } 100 101 int 102 X509_NAME_entry_count(X509_NAME *name) 103 { 104 if (name == NULL) 105 return (0); 106 return (sk_X509_NAME_ENTRY_num(name->entries)); 107 } 108 109 int 110 X509_NAME_get_index_by_NID(X509_NAME *name, int nid, int lastpos) 111 { 112 ASN1_OBJECT *obj; 113 114 obj = OBJ_nid2obj(nid); 115 if (obj == NULL) 116 return (-2); 117 return (X509_NAME_get_index_by_OBJ(name, obj, lastpos)); 118 } 119 120 /* NOTE: you should be passsing -1, not 0 as lastpos */ 121 int 122 X509_NAME_get_index_by_OBJ(X509_NAME *name, ASN1_OBJECT *obj, int lastpos) 123 { 124 int n; 125 X509_NAME_ENTRY *ne; 126 STACK_OF(X509_NAME_ENTRY) *sk; 127 128 if (name == NULL) 129 return (-1); 130 if (lastpos < 0) 131 lastpos = -1; 132 sk = name->entries; 133 n = sk_X509_NAME_ENTRY_num(sk); 134 for (lastpos++; lastpos < n; lastpos++) { 135 ne = sk_X509_NAME_ENTRY_value(sk, lastpos); 136 if (OBJ_cmp(ne->object, obj) == 0) 137 return (lastpos); 138 } 139 return (-1); 140 } 141 142 X509_NAME_ENTRY * 143 X509_NAME_get_entry(X509_NAME *name, int loc) 144 { 145 if (name == NULL || sk_X509_NAME_ENTRY_num(name->entries) <= loc || 146 loc < 0) 147 return (NULL); 148 else 149 return (sk_X509_NAME_ENTRY_value(name->entries, loc)); 150 } 151 152 X509_NAME_ENTRY * 153 X509_NAME_delete_entry(X509_NAME *name, int loc) 154 { 155 X509_NAME_ENTRY *ret; 156 int i, n, set_prev, set_next; 157 STACK_OF(X509_NAME_ENTRY) *sk; 158 159 if (name == NULL || sk_X509_NAME_ENTRY_num(name->entries) <= loc || 160 loc < 0) 161 return (NULL); 162 sk = name->entries; 163 ret = sk_X509_NAME_ENTRY_delete(sk, loc); 164 n = sk_X509_NAME_ENTRY_num(sk); 165 name->modified = 1; 166 if (loc == n) 167 return (ret); 168 169 /* else we need to fixup the set field */ 170 if (loc != 0) 171 set_prev = (sk_X509_NAME_ENTRY_value(sk, loc - 1))->set; 172 else 173 set_prev = ret->set - 1; 174 set_next = sk_X509_NAME_ENTRY_value(sk, loc)->set; 175 176 /* set_prev is the previous set 177 * set is the current set 178 * set_next is the following 179 * prev 1 1 1 1 1 1 1 1 180 * set 1 1 2 2 181 * next 1 1 2 2 2 2 3 2 182 * so basically only if prev and next differ by 2, then 183 * re-number down by 1 */ 184 if (set_prev + 1 < set_next) 185 for (i = loc; i < n; i++) 186 sk_X509_NAME_ENTRY_value(sk, i)->set--; 187 return (ret); 188 } 189 190 int 191 X509_NAME_add_entry_by_OBJ(X509_NAME *name, ASN1_OBJECT *obj, int type, 192 unsigned char *bytes, int len, int loc, int set) 193 { 194 X509_NAME_ENTRY *ne; 195 int ret; 196 197 ne = X509_NAME_ENTRY_create_by_OBJ(NULL, obj, type, bytes, len); 198 if (!ne) 199 return 0; 200 ret = X509_NAME_add_entry(name, ne, loc, set); 201 X509_NAME_ENTRY_free(ne); 202 return ret; 203 } 204 205 int 206 X509_NAME_add_entry_by_NID(X509_NAME *name, int nid, int type, 207 unsigned char *bytes, int len, int loc, int set) 208 { 209 X509_NAME_ENTRY *ne; 210 int ret; 211 212 ne = X509_NAME_ENTRY_create_by_NID(NULL, nid, type, bytes, len); 213 if (!ne) 214 return 0; 215 ret = X509_NAME_add_entry(name, ne, loc, set); 216 X509_NAME_ENTRY_free(ne); 217 return ret; 218 } 219 220 int 221 X509_NAME_add_entry_by_txt(X509_NAME *name, const char *field, int type, 222 const unsigned char *bytes, int len, int loc, int set) 223 { 224 X509_NAME_ENTRY *ne; 225 int ret; 226 227 ne = X509_NAME_ENTRY_create_by_txt(NULL, field, type, bytes, len); 228 if (!ne) 229 return 0; 230 ret = X509_NAME_add_entry(name, ne, loc, set); 231 X509_NAME_ENTRY_free(ne); 232 return ret; 233 } 234 235 /* if set is -1, append to previous set, 0 'a new one', and 1, 236 * prepend to the guy we are about to stomp on. */ 237 int 238 X509_NAME_add_entry(X509_NAME *name, X509_NAME_ENTRY *ne, int loc, int set) 239 { 240 X509_NAME_ENTRY *new_name = NULL; 241 int n, i, inc; 242 STACK_OF(X509_NAME_ENTRY) *sk; 243 244 if (name == NULL) 245 return (0); 246 sk = name->entries; 247 n = sk_X509_NAME_ENTRY_num(sk); 248 if (loc > n) 249 loc = n; 250 else if (loc < 0) 251 loc = n; 252 253 name->modified = 1; 254 255 if (set == -1) { 256 if (loc == 0) { 257 set = 0; 258 inc = 1; 259 } else { 260 set = sk_X509_NAME_ENTRY_value(sk, loc - 1)->set; 261 inc = 0; 262 } 263 } else /* if (set >= 0) */ { 264 if (loc >= n) { 265 if (loc != 0) 266 set = sk_X509_NAME_ENTRY_value(sk, loc - 1)->set + 1; 267 else 268 set = 0; 269 } else 270 set = sk_X509_NAME_ENTRY_value(sk, loc)->set; 271 inc = (set == 0) ? 1 : 0; 272 } 273 274 if ((new_name = X509_NAME_ENTRY_dup(ne)) == NULL) 275 goto err; 276 new_name->set = set; 277 if (!sk_X509_NAME_ENTRY_insert(sk, new_name, loc)) { 278 X509err(X509_F_X509_NAME_ADD_ENTRY, ERR_R_MALLOC_FAILURE); 279 goto err; 280 } 281 if (inc) { 282 n = sk_X509_NAME_ENTRY_num(sk); 283 for (i = loc + 1; i < n; i++) 284 sk_X509_NAME_ENTRY_value(sk, i - 1)->set += 1; 285 } 286 return (1); 287 288 err: 289 if (new_name != NULL) 290 X509_NAME_ENTRY_free(new_name); 291 return (0); 292 } 293 294 X509_NAME_ENTRY * 295 X509_NAME_ENTRY_create_by_txt(X509_NAME_ENTRY **ne, 296 const char *field, int type, const unsigned char *bytes, int len) 297 { 298 ASN1_OBJECT *obj; 299 X509_NAME_ENTRY *nentry; 300 301 obj = OBJ_txt2obj(field, 0); 302 if (obj == NULL) { 303 X509err(X509_F_X509_NAME_ENTRY_CREATE_BY_TXT, 304 X509_R_INVALID_FIELD_NAME); 305 ERR_asprintf_error_data("name=%s", field); 306 return (NULL); 307 } 308 nentry = X509_NAME_ENTRY_create_by_OBJ(ne, obj, type, bytes, len); 309 ASN1_OBJECT_free(obj); 310 return nentry; 311 } 312 313 X509_NAME_ENTRY * 314 X509_NAME_ENTRY_create_by_NID(X509_NAME_ENTRY **ne, int nid, int type, 315 unsigned char *bytes, int len) 316 { 317 ASN1_OBJECT *obj; 318 X509_NAME_ENTRY *nentry; 319 320 obj = OBJ_nid2obj(nid); 321 if (obj == NULL) { 322 X509err(X509_F_X509_NAME_ENTRY_CREATE_BY_NID, 323 X509_R_UNKNOWN_NID); 324 return (NULL); 325 } 326 nentry = X509_NAME_ENTRY_create_by_OBJ(ne, obj, type, bytes, len); 327 ASN1_OBJECT_free(obj); 328 return nentry; 329 } 330 331 X509_NAME_ENTRY * 332 X509_NAME_ENTRY_create_by_OBJ(X509_NAME_ENTRY **ne, ASN1_OBJECT *obj, int type, 333 const unsigned char *bytes, int len) 334 { 335 X509_NAME_ENTRY *ret; 336 337 if ((ne == NULL) || (*ne == NULL)) { 338 if ((ret = X509_NAME_ENTRY_new()) == NULL) 339 return (NULL); 340 } else 341 ret= *ne; 342 343 if (!X509_NAME_ENTRY_set_object(ret, obj)) 344 goto err; 345 if (!X509_NAME_ENTRY_set_data(ret, type, bytes, len)) 346 goto err; 347 348 if ((ne != NULL) && (*ne == NULL)) 349 *ne = ret; 350 return (ret); 351 352 err: 353 if ((ne == NULL) || (ret != *ne)) 354 X509_NAME_ENTRY_free(ret); 355 return (NULL); 356 } 357 358 int 359 X509_NAME_ENTRY_set_object(X509_NAME_ENTRY *ne, ASN1_OBJECT *obj) 360 { 361 if ((ne == NULL) || (obj == NULL)) { 362 X509err(X509_F_X509_NAME_ENTRY_SET_OBJECT, 363 ERR_R_PASSED_NULL_PARAMETER); 364 return (0); 365 } 366 ASN1_OBJECT_free(ne->object); 367 ne->object = OBJ_dup(obj); 368 return ((ne->object == NULL) ? 0 : 1); 369 } 370 371 int 372 X509_NAME_ENTRY_set_data(X509_NAME_ENTRY *ne, int type, 373 const unsigned char *bytes, int len) 374 { 375 int i; 376 377 if ((ne == NULL) || ((bytes == NULL) && (len != 0))) 378 return (0); 379 if ((type > 0) && (type & MBSTRING_FLAG)) 380 return ASN1_STRING_set_by_NID(&ne->value, bytes, len, type, 381 OBJ_obj2nid(ne->object)) ? 1 : 0; 382 if (len < 0) 383 len = strlen((const char *)bytes); 384 i = ASN1_STRING_set(ne->value, bytes, len); 385 if (!i) 386 return (0); 387 if (type != V_ASN1_UNDEF) { 388 if (type == V_ASN1_APP_CHOOSE) 389 ne->value->type = ASN1_PRINTABLE_type(bytes, len); 390 else 391 ne->value->type = type; 392 } 393 return (1); 394 } 395 396 ASN1_OBJECT * 397 X509_NAME_ENTRY_get_object(X509_NAME_ENTRY *ne) 398 { 399 if (ne == NULL) 400 return (NULL); 401 return (ne->object); 402 } 403 404 ASN1_STRING * 405 X509_NAME_ENTRY_get_data(X509_NAME_ENTRY *ne) 406 { 407 if (ne == NULL) 408 return (NULL); 409 return (ne->value); 410 } 411