2 * Copyright (C) 2008 Martin Willi
3 * Hochschule fuer Technik Rapperswil
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 #include "stroke_cred.h"
19 #include "stroke_shared_key.h"
24 #include <credentials/certificates/x509.h>
25 #include <credentials/certificates/crl.h>
26 #include <credentials/certificates/ac.h>
27 #include <utils/linked_list.h>
28 #include <utils/mutex.h>
29 #include <utils/lexparser.h>
33 /* configuration directories and files */
34 #define CONFIG_DIR IPSEC_CONFDIR
35 #define IPSEC_D_DIR CONFIG_DIR "/ipsec.d"
36 #define PRIVATE_KEY_DIR IPSEC_D_DIR "/private"
37 #define CERTIFICATE_DIR IPSEC_D_DIR "/certs"
38 #define CA_CERTIFICATE_DIR IPSEC_D_DIR "/cacerts"
39 #define AA_CERTIFICATE_DIR IPSEC_D_DIR "/aacerts"
40 #define ATTR_CERTIFICATE_DIR IPSEC_D_DIR "/acerts"
41 #define OCSP_CERTIFICATE_DIR IPSEC_D_DIR "/ocspcerts"
42 #define CRL_DIR IPSEC_D_DIR "/crls"
43 #define SECRETS_FILE CONFIG_DIR "/ipsec.secrets"
45 typedef struct private_stroke_cred_t private_stroke_cred_t
;
48 * private data of stroke_cred
50 struct private_stroke_cred_t
{
58 * list of trusted peer/signer/CA certificates (certificate_t)
63 * list of shared secrets (private_shared_key_t)
65 linked_list_t
*shared
;
68 * list of private keys (private_key_t)
70 linked_list_t
*private;
73 * mutex to lock lists above
84 * data to pass to various filters
87 private_stroke_cred_t
*this;
92 * destroy id enumerator data and unlock list
94 static void id_data_destroy(id_data_t
*data
)
96 data
->this->mutex
->unlock(data
->this->mutex
);
101 * filter function for private key enumerator
103 static bool private_filter(id_data_t
*data
,
104 private_key_t
**in
, private_key_t
**out
)
106 identification_t
*candidate
;
109 if (data
->id
== NULL
)
114 type
= data
->id
->get_type(data
->id
);
115 if (type
== ID_KEY_ID
)
116 { /* handle ID_KEY_ID as a ID_PUBKEY_SHA1 */
117 type
= ID_PUBKEY_SHA1
;
119 candidate
= (*in
)->get_id(*in
, type
);
121 chunk_equals(candidate
->get_encoding(candidate
),
122 data
->id
->get_encoding(data
->id
)))
131 * Implements credential_set_t.create_private_enumerator
133 static enumerator_t
* create_private_enumerator(private_stroke_cred_t
*this,
134 key_type_t type
, identification_t
*id
)
138 data
= malloc_thing(id_data_t
);
142 this->mutex
->lock(this->mutex
);
143 return enumerator_create_filter(this->private->create_enumerator(this->private),
144 (void*)private_filter
, data
,
145 (void*)id_data_destroy
);
149 * filter function for certs enumerator
151 static bool certs_filter(id_data_t
*data
, certificate_t
**in
, certificate_t
**out
)
153 public_key_t
*public;
154 identification_t
*candidate
;
155 certificate_t
*cert
= *in
;
156 certificate_type_t type
= cert
->get_type(cert
);
158 if (type
== CERT_X509_CRL
|| type
== CERT_X509_AC
)
163 if (data
->id
== NULL
|| cert
->has_subject(cert
, data
->id
))
169 public = (cert
)->get_public_key(cert
);
172 candidate
= public->get_id(public, data
->id
->get_type(data
->id
));
173 if (candidate
&& data
->id
->equals(data
->id
, candidate
))
175 public->destroy(public);
179 public->destroy(public);
185 * filter function for crl enumerator
187 static bool crl_filter(id_data_t
*data
, certificate_t
**in
, certificate_t
**out
)
189 certificate_t
*cert
= *in
;
191 if (cert
->get_type(cert
) != CERT_X509_CRL
)
196 if (data
->id
== NULL
|| cert
->has_issuer(cert
, data
->id
))
205 * filter function for attribute certificate enumerator
207 static bool ac_filter(id_data_t
*data
, certificate_t
**in
, certificate_t
**out
)
209 certificate_t
*cert
= *in
;
211 if (cert
->get_type(cert
) != CERT_X509_AC
)
216 if (data
->id
== NULL
|| cert
->has_subject(cert
, data
->id
))
225 * Implements credential_set_t.create_cert_enumerator
227 static enumerator_t
* create_cert_enumerator(private_stroke_cred_t
*this,
228 certificate_type_t cert
, key_type_t key
,
229 identification_t
*id
, bool trusted
)
233 if (cert
== CERT_X509_CRL
|| cert
== CERT_X509_AC
)
239 data
= malloc_thing(id_data_t
);
243 this->mutex
->lock(this->mutex
);
244 return enumerator_create_filter(this->certs
->create_enumerator(this->certs
),
245 (cert
== CERT_X509_CRL
)?
(void*)crl_filter
: (void*)ac_filter
,
246 data
, (void*)id_data_destroy
);
248 if (cert
!= CERT_X509
&& cert
!= CERT_ANY
)
249 { /* we only have X509 certificates. TODO: ACs? */
252 data
= malloc_thing(id_data_t
);
256 this->mutex
->lock(this->mutex
);
257 return enumerator_create_filter(this->certs
->create_enumerator(this->certs
),
258 (void*)certs_filter
, data
,
259 (void*)id_data_destroy
);
263 private_stroke_cred_t
*this;
264 identification_t
*me
;
265 identification_t
*other
;
266 shared_key_type_t type
;
270 * free shared key enumerator data and unlock list
272 static void shared_data_destroy(shared_data_t
*data
)
274 data
->this->mutex
->unlock(data
->this->mutex
);
279 * filter function for certs enumerator
281 static bool shared_filter(shared_data_t
*data
,
282 stroke_shared_key_t
**in
, shared_key_t
**out
,
283 void **unused1
, id_match_t
*me
,
284 void **unused2
, id_match_t
*other
)
286 id_match_t my_match
, other_match
;
287 stroke_shared_key_t
*stroke
= *in
;
288 shared_key_t
*shared
= &stroke
->shared
;
290 if (data
->type
!= SHARED_ANY
&& shared
->get_type(shared
) != data
->type
)
295 my_match
= stroke
->has_owner(stroke
, data
->me
);
296 other_match
= stroke
->has_owner(stroke
, data
->other
);
297 if (!my_match
&& !other_match
)
308 *other
= other_match
;
314 * Implements credential_set_t.create_shared_enumerator
316 static enumerator_t
* create_shared_enumerator(private_stroke_cred_t
*this,
317 shared_key_type_t type
, identification_t
*me
,
318 identification_t
*other
)
320 shared_data_t
*data
= malloc_thing(shared_data_t
);
326 this->mutex
->lock(this->mutex
);
327 return enumerator_create_filter(this->shared
->create_enumerator(this->shared
),
328 (void*)shared_filter
, data
,
329 (void*)shared_data_destroy
);
333 * Add a certificate to chain
335 static certificate_t
* add_cert(private_stroke_cred_t
*this, certificate_t
*cert
)
337 certificate_t
*current
;
338 enumerator_t
*enumerator
;
341 this->mutex
->lock(this->mutex
);
342 enumerator
= this->certs
->create_enumerator(this->certs
);
343 while (enumerator
->enumerate(enumerator
, (void**)¤t
))
345 if (current
->equals(current
, cert
))
347 /* cert already in queue */
354 enumerator
->destroy(enumerator
);
358 this->certs
->insert_last(this->certs
, cert
);
360 this->mutex
->unlock(this->mutex
);
365 * Implementation of stroke_cred_t.load_ca.
367 static certificate_t
* load_ca(private_stroke_cred_t
*this, char *filename
)
372 if (*filename
== '/')
374 snprintf(path
, sizeof(path
), "%s", filename
);
378 snprintf(path
, sizeof(path
), "%s/%s", CA_CERTIFICATE_DIR
, filename
);
381 cert
= lib
->creds
->create(lib
->creds
,
382 CRED_CERTIFICATE
, CERT_X509
,
383 BUILD_FROM_FILE
, path
,
384 BUILD_X509_FLAG
, X509_CA
,
388 return (certificate_t
*)add_cert(this, cert
);
394 * Add X.509 CRL to chain
396 static bool add_crl(private_stroke_cred_t
*this, crl_t
* crl
)
398 certificate_t
*current
, *cert
= &crl
->certificate
;
399 enumerator_t
*enumerator
;
400 bool new = TRUE
, found
= FALSE
;
402 this->mutex
->lock(this->mutex
);
403 enumerator
= this->certs
->create_enumerator(this->certs
);
404 while (enumerator
->enumerate(enumerator
, (void**)¤t
))
406 if (current
->get_type(current
) == CERT_X509_CRL
)
408 crl_t
*crl_c
= (crl_t
*)current
;
409 identification_t
*authkey
= crl
->get_authKeyIdentifier(crl
);
410 identification_t
*authkey_c
= crl_c
->get_authKeyIdentifier(crl_c
);
412 /* if compare authorityKeyIdentifiers if available */
413 if (authkey
!= NULL
&& authkey_c
!= NULL
&&
414 authkey
->equals(authkey
, authkey_c
))
420 identification_t
*issuer
= cert
->get_issuer(cert
);
421 identification_t
*issuer_c
= current
->get_issuer(current
);
423 /* otherwise compare issuer distinguished names */
424 if (issuer
->equals(issuer
, issuer_c
))
431 new = cert
->is_newer(cert
, current
);
434 this->certs
->remove_at(this->certs
, enumerator
);
444 enumerator
->destroy(enumerator
);
448 this->certs
->insert_last(this->certs
, cert
);
450 this->mutex
->unlock(this->mutex
);
455 * Add X.509 attribute certificate to chain
457 static bool add_ac(private_stroke_cred_t
*this, ac_t
* ac
)
459 certificate_t
*cert
= &ac
->certificate
;
461 this->mutex
->lock(this->mutex
);
462 this->certs
->insert_last(this->certs
, cert
);
463 this->mutex
->unlock(this->mutex
);
468 * Implementation of stroke_cred_t.load_peer.
470 static certificate_t
* load_peer(private_stroke_cred_t
*this, char *filename
)
475 if (*filename
== '/')
477 snprintf(path
, sizeof(path
), "%s", filename
);
481 snprintf(path
, sizeof(path
), "%s/%s", CERTIFICATE_DIR
, filename
);
484 cert
= lib
->creds
->create(lib
->creds
,
485 CRED_CERTIFICATE
, CERT_X509
,
486 BUILD_FROM_FILE
, path
,
491 cert
= add_cert(this, cert
);
492 return cert
->get_ref(cert
);
498 * load trusted certificates from a directory
500 static void load_certdir(private_stroke_cred_t
*this, char *path
,
501 certificate_type_t type
, x509_flag_t flag
)
506 enumerator_t
*enumerator
= enumerator_create_directory(path
);
510 DBG1(DBG_CFG
, " reading directory failed");
514 while (enumerator
->enumerate(enumerator
, NULL
, &file
, &st
))
518 if (!S_ISREG(st
.st_mode
))
520 /* skip special file */
526 cert
= lib
->creds
->create(lib
->creds
,
527 CRED_CERTIFICATE
, CERT_X509
,
528 BUILD_FROM_FILE
, file
,
529 BUILD_X509_FLAG
, flag
,
533 add_cert(this, cert
);
537 cert
= lib
->creds
->create(lib
->creds
,
538 CRED_CERTIFICATE
, CERT_X509_CRL
,
539 BUILD_FROM_FILE
, file
,
543 add_crl(this, (crl_t
*)cert
);
547 cert
= lib
->creds
->create(lib
->creds
,
548 CRED_CERTIFICATE
, CERT_X509_AC
,
549 BUILD_FROM_FILE
, file
,
553 add_ac(this, (ac_t
*)cert
);
560 enumerator
->destroy(enumerator
);
564 * Implementation of credential_set_t.cache_cert.
566 static void cache_cert(private_stroke_cred_t
*this, certificate_t
*cert
)
568 if (cert
->get_type(cert
) == CERT_X509_CRL
&& this->cachecrl
)
570 /* CRLs get written to /etc/ipsec.d/crls/authkeyId.crl */
571 crl_t
*crl
= (crl_t
*)cert
;
574 if (add_crl(this, crl
))
578 identification_t
*id
;
580 id
= crl
->get_authKeyIdentifier(crl
);
581 chunk
= id
->get_encoding(id
);
582 hex
= chunk_to_hex(chunk
, NULL
, FALSE
);
583 snprintf(buf
, sizeof(buf
), "%s/%s.crl", CRL_DIR
, hex
);
586 chunk
= cert
->get_encoding(cert
);
587 if (chunk_write(chunk
, buf
, 022, TRUE
))
589 DBG1(DBG_CFG
, " written crl to '%s'", buf
);
593 DBG1(DBG_CFG
, " writing crl to '%s' failed", buf
);
601 * Implementation of stroke_cred_t.cachecrl.
603 static void cachecrl(private_stroke_cred_t
*this, bool enabled
)
605 DBG1(DBG_CFG
, "crl caching to %s %s",
606 CRL_DIR
, enabled ?
"enabled" : "disabled");
607 this->cachecrl
= enabled
;
612 * Convert a string of characters into a binary secret
613 * A string between single or double quotes is treated as ASCII characters
614 * A string prepended by 0x is treated as HEX and prepended by 0s as Base64
616 static err_t
extract_secret(chunk_t
*secret
, chunk_t
*line
)
619 char delimiter
= ' ';
622 if (!eat_whitespace(line
))
624 return "missing secret";
627 if (*line
->ptr
== '\'' || *line
->ptr
== '"')
630 delimiter
= *line
->ptr
;
631 line
->ptr
++; line
->len
--;
634 if (!extract_token(&raw_secret
, delimiter
, line
))
636 if (delimiter
== ' ')
642 return "missing second delimiter";
648 /* treat as an ASCII string */
649 *secret
= chunk_clone(raw_secret
);
652 /* treat 0x as hex, 0s as base64 */
653 if (raw_secret
.len
> 2)
655 if (strncasecmp("0x", raw_secret
.ptr
, 2) == 0)
657 *secret
= chunk_from_hex(chunk_skip(raw_secret
, 2), NULL
);
660 if (strncasecmp("0s", raw_secret
.ptr
, 2) == 0)
662 *secret
= chunk_from_base64(chunk_skip(raw_secret
, 2), NULL
);
666 *secret
= chunk_clone(raw_secret
);
671 * reload ipsec.secrets
673 static void load_secrets(private_stroke_cred_t
*this)
677 chunk_t chunk
, src
, line
;
679 private_key_t
*private;
680 shared_key_t
*shared
;
682 DBG1(DBG_CFG
, "loading secrets from '%s'", SECRETS_FILE
);
684 fd
= fopen(SECRETS_FILE
, "r");
687 DBG1(DBG_CFG
, "opening secrets file '%s' failed");
691 /* TODO: do error checks */
692 fseek(fd
, 0, SEEK_END
);
693 chunk
.len
= ftell(fd
);
695 chunk
.ptr
= malloc(chunk
.len
);
696 bytes
= fread(chunk
.ptr
, 1, chunk
.len
, fd
);
700 this->mutex
->lock(this->mutex
);
701 while (this->shared
->remove_last(this->shared
,
702 (void**)&shared
) == SUCCESS
)
704 shared
->destroy(shared
);
706 while (this->private->remove_last(this->private,
707 (void**)&private) == SUCCESS
)
709 private->destroy(private);
712 while (fetchline(&src
, &line
))
715 shared_key_type_t type
;
719 if (!eat_whitespace(&line
))
723 if (!extract_last_token(&ids
, ':', &line
))
725 DBG1(DBG_CFG
, "line %d: missing ':' separator", line_nr
);
728 /* NULL terminate the ids string by replacing the : separator */
729 *(ids
.ptr
+ ids
.len
) = '\0';
731 if (!eat_whitespace(&line
) || !extract_token(&token
, ' ', &line
))
733 DBG1(DBG_CFG
, "line %d: missing token", line_nr
);
736 if (match("RSA", &token
) || match("ECDSA", &token
))
740 chunk_t secret
= chunk_empty
;
743 chunk_t chunk
= chunk_empty
;
744 key_type_t key_type
= match("RSA", &token
) ? KEY_RSA
: KEY_ECDSA
;
746 err_t ugh
= extract_value(&filename
, &line
);
750 DBG1(DBG_CFG
, "line %d: %s", line_nr
, ugh
);
753 if (filename
.len
== 0)
755 DBG1(DBG_CFG
, "line %d: empty filename", line_nr
);
758 if (*filename
.ptr
== '/')
760 /* absolute path name */
761 snprintf(path
, sizeof(path
), "%.*s", filename
.len
, filename
.ptr
);
765 /* relative path name */
766 snprintf(path
, sizeof(path
), "%s/%.*s", PRIVATE_KEY_DIR
,
767 filename
.len
, filename
.ptr
);
770 /* check for optional passphrase */
771 if (eat_whitespace(&line
))
773 ugh
= extract_secret(&secret
, &line
);
776 DBG1(DBG_CFG
, "line %d: malformed passphrase: %s", line_nr
, ugh
);
781 if (pem_asn1_load_file(path
, &secret
, &chunk
, &pgp
))
783 key
= lib
->creds
->create(lib
->creds
, CRED_PRIVATE_KEY
, key_type
,
784 BUILD_BLOB_ASN1_DER
, chunk
, BUILD_END
);
787 DBG1(DBG_CFG
, " loaded private key file '%s'", path
);
788 this->private->insert_last(this->private, key
);
791 chunk_clear(&secret
);
793 else if ((match("PSK", &token
) && (type
= SHARED_IKE
)) ||
794 (match("EAP", &token
) && (type
= SHARED_EAP
)) ||
795 (match("XAUTH", &token
) && (type
= SHARED_EAP
)) ||
796 (match("PIN", &token
) && (type
= SHARED_PIN
)))
798 stroke_shared_key_t
*shared_key
;
799 chunk_t secret
= chunk_empty
;
802 err_t ugh
= extract_secret(&secret
, &line
);
805 DBG1(DBG_CFG
, "line %d: malformed secret: %s", line_nr
, ugh
);
808 shared_key
= stroke_shared_key_create(type
, secret
);
809 DBG1(DBG_CFG
, " loaded %N secret for %s", shared_key_type_names
, type
,
810 ids
.len
> 0 ?
(char*)ids
.ptr
: "%any");
811 DBG4(DBG_CFG
, " secret: %#B", &secret
);
813 this->shared
->insert_last(this->shared
, shared_key
);
817 identification_t
*peer_id
;
819 ugh
= extract_value(&id
, &ids
);
822 DBG1(DBG_CFG
, "line %d: %s", line_nr
, ugh
);
830 /* NULL terminate the ID string */
831 *(id
.ptr
+ id
.len
) = '\0';
833 peer_id
= identification_create_from_string(id
.ptr
);
836 DBG1(DBG_CFG
, "line %d: malformed ID: %s", line_nr
, id
.ptr
);
839 if (peer_id
->get_type(peer_id
) == ID_ANY
)
841 peer_id
->destroy(peer_id
);
845 shared_key
->add_owner(shared_key
, peer_id
);
850 shared_key
->add_owner(shared_key
,
851 identification_create_from_encoding(ID_ANY
, chunk_empty
));
856 DBG1(DBG_CFG
, "line %d: token must be either "
857 "RSA, EC, PSK, EAP, or PIN", line_nr
);
862 this->mutex
->unlock(this->mutex
);
867 * load all certificates from ipsec.d
869 static void load_certs(private_stroke_cred_t
*this)
871 DBG1(DBG_CFG
, "loading ca certificates from '%s'",
873 load_certdir(this, CA_CERTIFICATE_DIR
, CERT_X509
, X509_CA
);
875 DBG1(DBG_CFG
, "loading aa certificates from '%s'",
877 load_certdir(this, AA_CERTIFICATE_DIR
, CERT_X509
, X509_AA
);
879 DBG1(DBG_CFG
, "loading ocsp signer certificates from '%s'",
880 OCSP_CERTIFICATE_DIR
);
881 load_certdir(this, OCSP_CERTIFICATE_DIR
, CERT_X509
, X509_OCSP_SIGNER
);
883 DBG1(DBG_CFG
, "loading attribute certificates from '%s'",
884 ATTR_CERTIFICATE_DIR
);
885 load_certdir(this, ATTR_CERTIFICATE_DIR
, CERT_X509_AC
, 0);
887 DBG1(DBG_CFG
, "loading crls from '%s'",
889 load_certdir(this, CRL_DIR
, CERT_X509_CRL
, 0);
893 * Implementation of stroke_cred_t.reread.
895 static void reread(private_stroke_cred_t
*this, stroke_msg_t
*msg
)
897 if (msg
->reread
.flags
& REREAD_SECRETS
)
899 DBG1(DBG_CFG
, "rereading secrets");
902 if (msg
->reread
.flags
& REREAD_CACERTS
)
904 DBG1(DBG_CFG
, "rereading ca certificates from '%s'",
906 load_certdir(this, CA_CERTIFICATE_DIR
, CERT_X509
, X509_CA
);
908 if (msg
->reread
.flags
& REREAD_OCSPCERTS
)
910 DBG1(DBG_CFG
, "rereading ocsp signer certificates from '%s'",
911 OCSP_CERTIFICATE_DIR
);
912 load_certdir(this, OCSP_CERTIFICATE_DIR
, CERT_X509
,
915 if (msg
->reread
.flags
& REREAD_AACERTS
)
917 DBG1(DBG_CFG
, "rereading aa certificates from '%s'",
919 load_certdir(this, AA_CERTIFICATE_DIR
, CERT_X509
, X509_AA
);
921 if (msg
->reread
.flags
& REREAD_ACERTS
)
923 DBG1(DBG_CFG
, "rereading attribute certificates from '%s'",
924 ATTR_CERTIFICATE_DIR
);
925 load_certdir(this, ATTR_CERTIFICATE_DIR
, CERT_X509_AC
, 0);
927 if (msg
->reread
.flags
& REREAD_CRLS
)
929 DBG1(DBG_CFG
, "rereading crls from '%s'",
931 load_certdir(this, CRL_DIR
, CERT_X509_CRL
, 0);
936 * Implementation of stroke_cred_t.destroy
938 static void destroy(private_stroke_cred_t
*this)
940 this->certs
->destroy_offset(this->certs
, offsetof(certificate_t
, destroy
));
941 this->shared
->destroy_offset(this->shared
, offsetof(shared_key_t
, destroy
));
942 this->private->destroy_offset(this->private, offsetof(private_key_t
, destroy
));
943 this->mutex
->destroy(this->mutex
);
950 stroke_cred_t
*stroke_cred_create()
952 private_stroke_cred_t
*this = malloc_thing(private_stroke_cred_t
);
954 this->public.set
.create_private_enumerator
= (void*)create_private_enumerator
;
955 this->public.set
.create_cert_enumerator
= (void*)create_cert_enumerator
;
956 this->public.set
.create_shared_enumerator
= (void*)create_shared_enumerator
;
957 this->public.set
.create_cdp_enumerator
= (void*)return_null
;
958 this->public.set
.cache_cert
= (void*)cache_cert
;
959 this->public.reread
= (void(*)(stroke_cred_t
*, stroke_msg_t
*msg
))reread
;
960 this->public.load_ca
= (certificate_t
*(*)(stroke_cred_t
*, char *filename
))load_ca
;
961 this->public.load_peer
= (certificate_t
*(*)(stroke_cred_t
*, char *filename
))load_peer
;
962 this->public.cachecrl
= (void(*)(stroke_cred_t
*, bool enabled
))cachecrl
;
963 this->public.destroy
= (void(*)(stroke_cred_t
*))destroy
;
965 this->certs
= linked_list_create();
966 this->shared
= linked_list_create();
967 this->private = linked_list_create();
968 this->mutex
= mutex_create(MUTEX_RECURSIVE
);
973 this->cachecrl
= FALSE
;
975 return &this->public;