1 /*
2  * Copyright (c) 2009 NLNet Labs. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
19  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
21  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
23  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  */
26 
27 /**
28  * Hardware Security Module support.
29  *
30  */
31 
32 #include "daemon/engine.h"
33 #include "hsm.h"
34 #include "log.h"
35 #include "cryptoki_compat/pkcs11.h"
36 
37 static const char* hsm_str = "hsm";
38 
39 /**
40  * Clear key cache.
41  *
42  */
43 static void
lhsm_clear_key_cache(key_type * key)44 lhsm_clear_key_cache(key_type* key)
45 {
46     if (!key) {
47         return;
48     }
49     if (key->dnskey) {
50         /* DNSKEY still exists in zone */
51         key->dnskey = NULL;
52     }
53     if (key->params) {
54         hsm_sign_params_free(key->params);
55         key->params = NULL;
56     }
57 }
58 
59 static const libhsm_key_t*
keylookup(hsm_ctx_t * ctx,const char * locator)60 keylookup(hsm_ctx_t* ctx, const char* locator)
61 {
62     const libhsm_key_t* key;
63     key = keycache_lookup(ctx, locator);
64     if (key == NULL) {
65         char* error = hsm_get_error(ctx);
66             if (error) {
67                 ods_log_error("[%s] %s", hsm_str, error);
68                 free((void*)error);
69             }
70             /* could not find key */
71             ods_log_error("[%s] unable to get key: key %s not found", hsm_str, locator);
72     }
73     return key;
74 }
75 
76 /**
77  * Get key from one of the HSMs.
78  *
79  */
80 ods_status
lhsm_get_key(hsm_ctx_t * ctx,ldns_rdf * owner,key_type * key_id,int skip_hsm_access)81 lhsm_get_key(hsm_ctx_t* ctx, ldns_rdf* owner, key_type* key_id, int skip_hsm_access)
82 {
83     char *error = NULL;
84     int retries = 0;
85 
86     if (!owner || !key_id) {
87         ods_log_error("[%s] unable to get key: missing required elements",
88             hsm_str);
89         return ODS_STATUS_ASSERT_ERR;
90     }
91 
92 llibhsm_key_start:
93 
94     /* set parameters */
95     if (!key_id->params) {
96         key_id->params = hsm_sign_params_new();
97         if (key_id->params) {
98             key_id->params->owner = ldns_rdf_clone(owner);
99             key_id->params->algorithm = key_id->algorithm;
100             key_id->params->flags = key_id->flags;
101         } else {
102             /* could not create params */
103             ods_log_error("[%s] unable to get key: create params for key %s "
104                 "failed", hsm_str, key_id->locator?key_id->locator:"(null)");
105             return ODS_STATUS_ERR;
106         }
107     }
108     if (skip_hsm_access) return ODS_STATUS_OK;
109 
110     /* get dnskey */
111     if (!key_id->dnskey) {
112         key_id->dnskey = hsm_get_dnskey(ctx, keylookup(ctx, key_id->locator), key_id->params);
113     }
114     if (!key_id->dnskey) {
115         error = hsm_get_error(ctx);
116         if (error) {
117             ods_log_error("[%s] %s", hsm_str, error);
118             free((void*)error);
119         } else if (!retries) {
120             lhsm_clear_key_cache(key_id);
121             retries++;
122             goto llibhsm_key_start;
123         }
124         ods_log_error("[%s] unable to get key: hsm failed to create dnskey",
125             hsm_str);
126         return ODS_STATUS_ERR;
127     }
128     key_id->params->keytag = ldns_calc_keytag(key_id->dnskey);
129     return ODS_STATUS_OK;
130 }
131 
132 
133 /**
134  * Get RRSIG from one of the HSMs, given a RRset and a key.
135  *
136  */
137 ldns_rr*
lhsm_sign(hsm_ctx_t * ctx,ldns_rr_list * rrset,key_type * key_id,ldns_rdf * owner,time_t inception,time_t expiration)138 lhsm_sign(hsm_ctx_t* ctx, ldns_rr_list* rrset, key_type* key_id,
139     ldns_rdf* owner, time_t inception, time_t expiration)
140 {
141     char* error = NULL;
142     ldns_rr* result = NULL;
143     hsm_sign_params_t* params = NULL;
144 
145     if (!owner || !key_id || !rrset || !inception || !expiration) {
146         ods_log_error("[%s] unable to sign: missing required elements",
147             hsm_str);
148         return NULL;
149     }
150     ods_log_assert(key_id->dnskey);
151     ods_log_assert(key_id->params);
152     /* adjust parameters */
153     params = hsm_sign_params_new();
154     params->owner = ldns_rdf_clone(key_id->params->owner);
155     params->algorithm = key_id->algorithm;
156     params->flags = key_id->flags;
157     params->inception = inception;
158     params->expiration = expiration;
159     params->keytag = key_id->params->keytag;
160     ods_log_deeebug("[%s] sign RRset[%i] with key %s tag %u", hsm_str,
161         ldns_rr_get_type(ldns_rr_list_rr(rrset, 0)),
162         key_id->locator?key_id->locator:"(null)", params->keytag);
163     result = hsm_sign_rrset(ctx, rrset, keylookup(ctx, key_id->locator), params);
164     hsm_sign_params_free(params);
165     if (!result) {
166         error = hsm_get_error(ctx);
167         if (error) {
168             ods_log_error("[%s] %s", hsm_str, error);
169             free((void*)error);
170         }
171         ods_log_crit("[%s] error signing rrset with libhsm", hsm_str);
172     }
173     return result;
174 }
175