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