3 * THE REGENTS OF THE UNIVERSITY OF MICHIGAN
6 * Permission is granted to use, copy, create derivative works
7 * and redistribute this software and such derivative works
8 * for any purpose, so long as the name of The University of
9 * Michigan is not used in any advertising or publicity
10 * pertaining to the use of distribution of this software
11 * without specific, written prior authorization. If the
12 * above copyright notice or any other identification of the
13 * University of Michigan is included in any copy of any
14 * portion of this software, then the disclaimer below must
17 * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
18 * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
19 * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
20 * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
21 * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
22 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
23 * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
24 * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
25 * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
26 * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
27 * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
32 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
48 free_list(char **list
)
55 for (i
= 0; list
[i
] != NULL
; i
++)
60 static krb5_error_code
61 copy_list(char ***dst
, char **src
)
73 for (i
= 0; src
[i
] != NULL
; i
++);
75 newlist
= calloc(1, (i
+ 1) * sizeof(*newlist
));
79 for (i
= 0; src
[i
] != NULL
; i
++) {
80 newlist
[i
] = strdup(src
[i
]);
81 if (newlist
[i
] == NULL
)
93 idtype2string(int idtype
)
95 /* Solaris Kerberos: Removed "break"s (lint) */
97 case IDTYPE_FILE
: return "FILE";
98 case IDTYPE_DIR
: return "DIR";
99 case IDTYPE_PKCS11
: return "PKCS11";
100 case IDTYPE_PKCS12
: return "PKCS12";
101 case IDTYPE_ENVVAR
: return "ENV";
102 default: return "INVALID";
107 catype2string(int catype
)
109 /* Solaris Kerberos: Removed "break"s (lint) */
111 case CATYPE_ANCHORS
: return "ANCHORS";
112 case CATYPE_INTERMEDIATES
: return "INTERMEDIATES";
113 case CATYPE_CRLS
: return "CRLS";
114 default: return "INVALID";
119 pkinit_init_identity_opts(pkinit_identity_opts
**idopts
)
121 pkinit_identity_opts
*opts
= NULL
;
124 opts
= (pkinit_identity_opts
*) calloc(1, sizeof(pkinit_identity_opts
));
128 opts
->identity
= NULL
;
129 opts
->anchors
= NULL
;
130 opts
->intermediates
= NULL
;
133 opts
->dn_mapping_file
= NULL
;
135 opts
->cert_filename
= NULL
;
136 opts
->key_filename
= NULL
;
137 #ifndef WITHOUT_PKCS11
138 opts
->p11_module_name
= NULL
;
139 opts
->slotid
= PK_NOSLOT
;
140 opts
->token_label
= NULL
;
141 opts
->cert_id_string
= NULL
;
142 opts
->cert_label
= NULL
;
152 pkinit_dup_identity_opts(pkinit_identity_opts
*src_opts
,
153 pkinit_identity_opts
**dest_opts
)
155 pkinit_identity_opts
*newopts
;
156 krb5_error_code retval
;
159 retval
= pkinit_init_identity_opts(&newopts
);
165 if (src_opts
->identity
!= NULL
) {
166 newopts
->identity
= strdup(src_opts
->identity
);
167 if (newopts
->identity
== NULL
)
171 retval
= copy_list(&newopts
->anchors
, src_opts
->anchors
);
175 retval
= copy_list(&newopts
->intermediates
,src_opts
->intermediates
);
179 retval
= copy_list(&newopts
->crls
, src_opts
->crls
);
183 if (src_opts
->ocsp
!= NULL
) {
184 newopts
->ocsp
= strdup(src_opts
->ocsp
);
185 if (newopts
->ocsp
== NULL
)
189 if (src_opts
->cert_filename
!= NULL
) {
190 newopts
->cert_filename
= strdup(src_opts
->cert_filename
);
191 if (newopts
->cert_filename
== NULL
)
195 if (src_opts
->key_filename
!= NULL
) {
196 newopts
->key_filename
= strdup(src_opts
->key_filename
);
197 if (newopts
->key_filename
== NULL
)
201 #ifndef WITHOUT_PKCS11
202 if (src_opts
->p11_module_name
!= NULL
) {
203 newopts
->p11_module_name
= strdup(src_opts
->p11_module_name
);
204 if (newopts
->p11_module_name
== NULL
)
208 newopts
->slotid
= src_opts
->slotid
;
210 if (src_opts
->token_label
!= NULL
) {
211 newopts
->token_label
= strdup(src_opts
->token_label
);
212 if (newopts
->token_label
== NULL
)
216 if (src_opts
->cert_id_string
!= NULL
) {
217 newopts
->cert_id_string
= strdup(src_opts
->cert_id_string
);
218 if (newopts
->cert_id_string
== NULL
)
222 if (src_opts
->cert_label
!= NULL
) {
223 newopts
->cert_label
= strdup(src_opts
->cert_label
);
224 if (newopts
->cert_label
== NULL
)
227 if (src_opts
->PIN
!= NULL
) {
228 newopts
->PIN
= strdup(src_opts
->PIN
);
229 if (newopts
->PIN
== NULL
)
235 *dest_opts
= newopts
;
238 pkinit_fini_identity_opts(newopts
);
243 pkinit_fini_identity_opts(pkinit_identity_opts
*idopts
)
248 free(idopts
->identity
);
249 free_list(idopts
->anchors
);
250 free_list(idopts
->intermediates
);
251 free_list(idopts
->crls
);
252 free_list(idopts
->identity_alt
);
254 free(idopts
->cert_filename
);
255 free(idopts
->key_filename
);
256 #ifndef WITHOUT_PKCS11
257 free(idopts
->p11_module_name
);
258 free(idopts
->token_label
);
259 free(idopts
->cert_id_string
);
260 free(idopts
->cert_label
);
261 if (idopts
->PIN
!= NULL
) {
262 (void) memset(idopts
->PIN
, 0, strlen(idopts
->PIN
));
269 #ifndef WITHOUT_PKCS11
271 static krb5_error_code
272 parse_pkcs11_options(krb5_context context
,
273 pkinit_identity_opts
*idopts
,
274 const char *residual
)
277 krb5_error_code retval
= ENOMEM
;
279 if (residual
== NULL
|| residual
[0] == '\0')
282 /* Split string into attr=value substrings */
283 s
= strdup(residual
);
287 for ((cp
= strtok(s
, ":")); cp
; (cp
= strtok(NULL
, ":"))) {
288 vp
= strchr(cp
, '=');
290 /* If there is no "=", this is a pkcs11 module name */
292 free(idopts
->p11_module_name
);
293 idopts
->p11_module_name
= strdup(cp
);
294 if (idopts
->p11_module_name
== NULL
)
299 if (!strcmp(cp
, "module_name")) {
300 free(idopts
->p11_module_name
);
301 idopts
->p11_module_name
= strdup(vp
);
302 if (idopts
->p11_module_name
== NULL
)
304 } else if (!strcmp(cp
, "slotid")) {
305 long slotid
= strtol(vp
, NULL
, 10);
306 if ((slotid
== LONG_MIN
|| slotid
== LONG_MAX
) && errno
!= 0) {
310 if ((long) (int) slotid
!= slotid
) {
314 idopts
->slotid
= slotid
;
315 } else if (!strcmp(cp
, "token")) {
316 free(idopts
->token_label
);
317 idopts
->token_label
= strdup(vp
);
318 if (idopts
->token_label
== NULL
)
320 } else if (!strcmp(cp
, "certid")) {
321 free(idopts
->cert_id_string
);
322 idopts
->cert_id_string
= strdup(vp
);
323 if (idopts
->cert_id_string
== NULL
)
325 } else if (!strcmp(cp
, "certlabel")) {
326 free(idopts
->cert_label
);
327 idopts
->cert_label
= strdup(vp
);
328 if (idopts
->cert_label
== NULL
)
340 static krb5_error_code
341 parse_fs_options(krb5_context context
,
342 pkinit_identity_opts
*idopts
,
343 const char *residual
)
345 char *certname
, *keyname
;
346 krb5_error_code retval
= ENOMEM
;
348 if (residual
== NULL
|| residual
[0] == '\0')
351 certname
= strdup(residual
);
352 if (certname
== NULL
)
355 certname
= strtok(certname
, ",");
356 keyname
= strtok(NULL
, ",");
358 idopts
->cert_filename
= strdup(certname
);
359 if (idopts
->cert_filename
== NULL
)
362 idopts
->key_filename
= strdup(keyname
? keyname
: certname
);
363 if (idopts
->key_filename
== NULL
)
373 static krb5_error_code
374 parse_pkcs12_options(krb5_context context
,
375 pkinit_identity_opts
*idopts
,
376 const char *residual
)
378 krb5_error_code retval
= ENOMEM
;
380 if (residual
== NULL
|| residual
[0] == '\0')
383 idopts
->cert_filename
= strdup(residual
);
384 if (idopts
->cert_filename
== NULL
)
387 idopts
->key_filename
= strdup(residual
);
388 if (idopts
->key_filename
== NULL
)
391 pkiDebug("%s: cert_filename '%s' key_filename '%s'\n",
392 __FUNCTION__
, idopts
->cert_filename
,
393 idopts
->key_filename
);
399 static krb5_error_code
400 process_option_identity(krb5_context context
,
401 pkinit_plg_crypto_context plg_cryptoctx
,
402 pkinit_req_crypto_context req_cryptoctx
,
403 pkinit_identity_opts
*idopts
,
404 pkinit_identity_crypto_context id_cryptoctx
,
407 const char *residual
;
409 krb5_error_code retval
= 0;
411 pkiDebug("%s: processing value '%s'\n",
412 __FUNCTION__
, value
? value
: "NULL");
416 residual
= strchr(value
, ':');
417 if (residual
!= NULL
) {
418 unsigned int typelen
;
419 residual
++; /* skip past colon */
420 typelen
= residual
- value
;
421 if (strncmp(value
, "FILE:", typelen
) == 0) {
422 idtype
= IDTYPE_FILE
;
423 #ifndef WITHOUT_PKCS11
424 } else if (strncmp(value
, "PKCS11:", typelen
) == 0) {
425 idtype
= IDTYPE_PKCS11
;
427 } else if (strncmp(value
, "PKCS12:", typelen
) == 0) {
428 idtype
= IDTYPE_PKCS12
;
429 } else if (strncmp(value
, "DIR:", typelen
) == 0) {
431 } else if (strncmp(value
, "ENV:", typelen
) == 0) {
432 idtype
= IDTYPE_ENVVAR
;
434 pkiDebug("%s: Unsupported type while processing '%s'\n",
435 __FUNCTION__
, value
);
436 krb5_set_error_message(context
, KRB5_PREAUTH_FAILED
,
437 "Unsupported type while processing '%s'\n",
439 return KRB5_PREAUTH_FAILED
;
442 idtype
= IDTYPE_FILE
;
446 idopts
->idtype
= idtype
;
447 pkiDebug("%s: idtype is %s\n", __FUNCTION__
, idtype2string(idopts
->idtype
));
449 case IDTYPE_ENVVAR
: {
450 /* Solaris Kerberos: Improved error messages */
451 char *envvar
= getenv(residual
);
452 if (envvar
== NULL
) {
453 krb5_set_error_message(context
, EINVAL
,
454 gettext("failed to find environmental variable \'%s\'"),
458 return process_option_identity(context
, plg_cryptoctx
,
459 req_cryptoctx
, idopts
, id_cryptoctx
,
461 /* Solaris Kerberos: not reached */
464 retval
= parse_fs_options(context
, idopts
, residual
);
467 retval
= parse_pkcs12_options(context
, idopts
, residual
);
469 #ifndef WITHOUT_PKCS11
471 retval
= parse_pkcs11_options(context
, idopts
, residual
);
475 idopts
->cert_filename
= strdup(residual
);
476 if (idopts
->cert_filename
== NULL
)
480 krb5_set_error_message(context
, KRB5_PREAUTH_FAILED
,
481 "Internal error parsing X509_user_identity\n");
488 static krb5_error_code
489 process_option_ca_crl(krb5_context context
,
490 pkinit_plg_crypto_context plg_cryptoctx
,
491 pkinit_req_crypto_context req_cryptoctx
,
492 pkinit_identity_opts
*idopts
,
493 pkinit_identity_crypto_context id_cryptoctx
,
498 unsigned int typelen
;
501 pkiDebug("%s: processing catype %s, value '%s'\n",
502 __FUNCTION__
, catype2string(catype
), value
);
503 residual
= strchr(value
, ':');
504 if (residual
== NULL
) {
505 pkiDebug("No type given for '%s'\n", value
);
508 residual
++; /* skip past colon */
509 typelen
= residual
- value
;
510 if (strncmp(value
, "FILE:", typelen
) == 0) {
511 idtype
= IDTYPE_FILE
;
512 } else if (strncmp(value
, "DIR:", typelen
) == 0) {
517 return crypto_load_cas_and_crls(context
,
520 idopts
, id_cryptoctx
,
521 idtype
, catype
, residual
);
524 static krb5_error_code
525 pkinit_identity_process_option(krb5_context context
,
526 pkinit_plg_crypto_context plg_cryptoctx
,
527 pkinit_req_crypto_context req_cryptoctx
,
528 pkinit_identity_opts
*idopts
,
529 pkinit_identity_crypto_context id_cryptoctx
,
533 krb5_error_code retval
= 0;
536 case PKINIT_ID_OPT_USER_IDENTITY
:
537 retval
= process_option_identity(context
, plg_cryptoctx
,
538 req_cryptoctx
, idopts
,
539 id_cryptoctx
, value
);
541 case PKINIT_ID_OPT_ANCHOR_CAS
:
542 retval
= process_option_ca_crl(context
, plg_cryptoctx
,
543 req_cryptoctx
, idopts
,
547 case PKINIT_ID_OPT_INTERMEDIATE_CAS
:
548 retval
= process_option_ca_crl(context
, plg_cryptoctx
,
549 req_cryptoctx
, idopts
,
551 value
, CATYPE_INTERMEDIATES
);
553 case PKINIT_ID_OPT_CRLS
:
554 retval
= process_option_ca_crl(context
, plg_cryptoctx
,
555 req_cryptoctx
, idopts
,
559 case PKINIT_ID_OPT_OCSP
:
570 pkinit_identity_initialize(krb5_context context
,
571 pkinit_plg_crypto_context plg_cryptoctx
,
572 pkinit_req_crypto_context req_cryptoctx
,
573 pkinit_identity_opts
*idopts
,
574 pkinit_identity_crypto_context id_cryptoctx
,
576 krb5_principal princ
)
578 krb5_error_code retval
= EINVAL
;
581 pkiDebug("%s: %p %p %p\n", __FUNCTION__
, context
, idopts
, id_cryptoctx
);
582 if (idopts
== NULL
|| id_cryptoctx
== NULL
)
586 * If identity was specified, use that. (For the kdc, this
587 * is specified as pkinit_identity in the kdc.conf. For users,
588 * this is specified on the command line via X509_user_identity.)
589 * If a user did not specify identity on the command line,
590 * then we will try alternatives which may have been specified
591 * in the config file.
593 if (idopts
->identity
!= NULL
) {
594 retval
= pkinit_identity_process_option(context
, plg_cryptoctx
,
595 req_cryptoctx
, idopts
,
597 PKINIT_ID_OPT_USER_IDENTITY
,
599 } else if (idopts
->identity_alt
!= NULL
) {
600 for (i
= 0; retval
!= 0 && idopts
->identity_alt
[i
] != NULL
; i
++)
601 retval
= pkinit_identity_process_option(context
, plg_cryptoctx
,
602 req_cryptoctx
, idopts
,
604 PKINIT_ID_OPT_USER_IDENTITY
,
605 idopts
->identity_alt
[i
]);
607 pkiDebug("%s: no user identity options specified\n", __FUNCTION__
);
613 retval
= crypto_load_certs(context
, plg_cryptoctx
, req_cryptoctx
,
614 idopts
, id_cryptoctx
, princ
, do_matching
);
619 retval
= pkinit_cert_matching(context
, plg_cryptoctx
, req_cryptoctx
,
620 id_cryptoctx
, princ
, TRUE
);
622 pkiDebug("%s: No matching certificate found\n", __FUNCTION__
);
623 (void) crypto_free_cert_info(context
, plg_cryptoctx
, req_cryptoctx
,
628 /* Tell crypto code to use the "default" */
629 retval
= crypto_cert_select_default(context
, plg_cryptoctx
,
630 req_cryptoctx
, id_cryptoctx
);
632 pkiDebug("%s: Failed while selecting default certificate\n",
634 (void) crypto_free_cert_info(context
, plg_cryptoctx
, req_cryptoctx
,
640 retval
= crypto_free_cert_info(context
, plg_cryptoctx
, req_cryptoctx
,
645 for (i
= 0; idopts
->anchors
!= NULL
&& idopts
->anchors
[i
] != NULL
; i
++) {
646 retval
= pkinit_identity_process_option(context
, plg_cryptoctx
,
647 req_cryptoctx
, idopts
,
649 PKINIT_ID_OPT_ANCHOR_CAS
,
654 for (i
= 0; idopts
->intermediates
!= NULL
655 && idopts
->intermediates
[i
] != NULL
; i
++) {
656 retval
= pkinit_identity_process_option(context
, plg_cryptoctx
,
657 req_cryptoctx
, idopts
,
659 PKINIT_ID_OPT_INTERMEDIATE_CAS
,
660 idopts
->intermediates
[i
]);
664 for (i
= 0; idopts
->crls
!= NULL
&& idopts
->crls
[i
] != NULL
; i
++) {
665 retval
= pkinit_identity_process_option(context
, plg_cryptoctx
,
666 req_cryptoctx
, idopts
,
673 if (idopts
->ocsp
!= NULL
) {
674 retval
= pkinit_identity_process_option(context
, plg_cryptoctx
,
675 req_cryptoctx
, idopts
,