1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 * 21 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 22 */ 23 24 /* 25 * KMF CN certificate-to-name mapper. 26 */ 27 28 #include <kmftypes.h> 29 #include <kmfapi.h> 30 #include <fcntl.h> 31 32 /* 33 * KMF uses long identifiers for RDN processing which makes it hard to keep 34 * cstyle cleanliness without using some auxiliary macros. Parameter 'x' is of 35 * the KMF_X509_NAME type. 36 */ 37 #define RDN_VALUE(x, i) \ 38 (&x.RelativeDistinguishedName[i].AttributeTypeAndValue->value) 39 40 #define RDN_OID(x, i) \ 41 (&x.RelativeDistinguishedName[i].AttributeTypeAndValue->type) 42 43 #define RDN_NPAIRS(x, i) (x.RelativeDistinguishedName[i].numberOfPairs) 44 45 /* Error codes specific to this mapper. */ 46 #define CN_MAPPER_CN_RDN_NOT_PRESENT 1 47 48 typedef struct cooked_opts { 49 int casesensitive; 50 } cooked_opts; 51 52 KMF_RETURN 53 mapper_initialize(KMF_HANDLE_T h, char *options) 54 { 55 cooked_opts *opts; 56 57 if ((opts = malloc(sizeof (cooked_opts))) == NULL) 58 return (KMF_ERR_MEMORY); 59 60 /* This is the default. */ 61 opts->casesensitive = B_FALSE; 62 63 if (options != NULL) { 64 if (strcmp(options, "casesensitive") == 0) 65 opts->casesensitive = B_TRUE; 66 } 67 68 kmf_set_mapper_options(h, opts); 69 70 return (KMF_OK); 71 } 72 73 void 74 mapper_finalize(KMF_HANDLE_T h) 75 { 76 void *opts; 77 78 if ((opts = kmf_get_mapper_options(h)) != NULL) 79 free(opts); 80 kmf_set_mapper_options(h, NULL); 81 } 82 83 /* 84 * The CN string returned in name.Data will be NULL-terminated. The caller is 85 * expected to free name->Data after use. 86 */ 87 KMF_RETURN 88 mapper_map_cert_to_name(KMF_HANDLE_T h, KMF_DATA *cert, KMF_DATA *name) 89 { 90 int i, j; 91 char *dn; 92 KMF_RETURN rv; 93 uchar_t *cn = NULL; 94 KMF_X509_NAME x509name; 95 96 kmf_set_mapper_lasterror(h, KMF_OK); 97 98 if ((rv = kmf_get_cert_subject_str(h, cert, &dn)) != KMF_OK) 99 return (rv); 100 101 if ((rv = kmf_dn_parser(dn, &x509name)) != KMF_OK) 102 return (rv); 103 104 /* Go through the list of RDNs and look for the CN. */ 105 for (i = 0; i < x509name.numberOfRDNs; ++i) { 106 for (j = 0; j < RDN_NPAIRS(x509name, i); ++j) { 107 KMF_OID *oid = RDN_OID(x509name, i); 108 KMF_DATA *data = RDN_VALUE(x509name, i); 109 110 if (oid == NULL) 111 continue; 112 113 /* Is this RDN a Common Name? */ 114 if (oid->Length == KMFOID_CommonName.Length && 115 memcmp(oid->Data, KMFOID_CommonName.Data, 116 oid->Length) == 0) { 117 if ((cn = malloc(data->Length + 1)) == NULL) { 118 kmf_free_dn(&x509name); 119 return (KMF_ERR_MEMORY); 120 } 121 (void) memcpy(cn, data->Data, data->Length); 122 /* Terminate the string. */ 123 cn[data->Length] = '\0'; 124 name->Length = data->Length + 1; 125 name->Data = cn; 126 goto finished; 127 } 128 } 129 } 130 131 finished: 132 kmf_free_dn(&x509name); 133 if (cn != NULL) 134 return (KMF_OK); 135 else { 136 kmf_set_mapper_lasterror(h, CN_MAPPER_CN_RDN_NOT_PRESENT); 137 return (KMF_ERR_INTERNAL); 138 } 139 } 140 141 /* 142 * Note that name_to_match->Data might or might not be NULL terminated. If 143 * mapped_name->Length returned is greater than zero the caller is expected to 144 * free mapped_name->Data after use. 145 */ 146 KMF_RETURN 147 mapper_match_cert_to_name(KMF_HANDLE_T h, KMF_DATA *cert, 148 KMF_DATA *name_to_match, KMF_DATA *mapped_name) 149 { 150 int ret; 151 KMF_RETURN rv; 152 KMF_DATA get_name; 153 cooked_opts *opts = NULL; 154 155 opts = (cooked_opts *)kmf_get_mapper_options(h); 156 157 /* Initialize the output parameter. */ 158 if (mapped_name != NULL) { 159 mapped_name->Length = 0; 160 mapped_name->Data = NULL; 161 } 162 163 if ((rv = mapper_map_cert_to_name(h, cert, &get_name)) != KMF_OK) 164 return (rv); 165 166 /* 167 * If name_to_match->Data is not NULL terminated, check that we have the 168 * same number of characters. 169 */ 170 if (name_to_match->Data[name_to_match->Length - 1] != '\0') 171 /* We know that get_name.Data is NULL terminated. */ 172 if (name_to_match->Length != get_name.Length - 1) 173 return (KMF_ERR_NAME_NOT_MATCHED); 174 175 /* 176 * Compare the strings. We must use name_to_match->Length in case 177 * name_to_match->Data was not NULL terminated. If we used 178 * get_name.Length we could overrun name_to_match->Data by one byte. 179 */ 180 if (opts->casesensitive == B_TRUE) 181 ret = strncmp((char *)name_to_match->Data, 182 (char *)get_name.Data, name_to_match->Length); 183 else 184 ret = strncasecmp((char *)name_to_match->Data, 185 (char *)get_name.Data, name_to_match->Length); 186 187 if (mapped_name != NULL) { 188 mapped_name->Length = get_name.Length; 189 mapped_name->Data = get_name.Data; 190 } else 191 kmf_free_data(&get_name); 192 193 if (ret == 0) 194 return (KMF_OK); 195 else 196 return (KMF_ERR_NAME_NOT_MATCHED); 197 } 198 199 /* The caller is responsible for freeing the error string when done with it. */ 200 KMF_RETURN 201 mapper_get_error_str(KMF_HANDLE_T h, char **errstr) 202 { 203 uint32_t lasterr; 204 205 lasterr = kmf_get_mapper_lasterror(h); 206 *errstr = NULL; 207 if (lasterr == 0) 208 return (KMF_ERR_MISSING_ERRCODE); 209 210 switch (lasterr) { 211 case CN_MAPPER_CN_RDN_NOT_PRESENT: 212 *errstr = (char *)strdup("CN_MAPPER_CN_RDN_NOT_PRESENT"); 213 break; 214 default: 215 *errstr = (char *)strdup("KMF_ERR_MISSING_MAPPER_ERRCODE"); 216 } 217 218 if (*errstr == NULL) 219 return (KMF_ERR_MEMORY); 220 221 return (KMF_OK); 222 } 223