Use of TPM 2.0 private keys for signatures via tpm plugin
[strongswan.git] / src / libtpmtss / plugins / tpm / tpm_private_key.c
1 /*
2 * Copyright (C) 2017 Andreas Steffen
3 * HSR Hochschule fuer Technik Rapperswil
4 *
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>.
9 *
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
13 * for more details.
14 */
15
16 #include "tpm_private_key.h"
17
18 #include <tpm_tss.h>
19 #include <utils/debug.h>
20
21 typedef struct private_tpm_private_key_t private_tpm_private_key_t;
22
23 /**
24 * Private data of an tpm_private_key_t object.
25 */
26 struct private_tpm_private_key_t {
27
28 /**
29 * Public tpm_private_key_t interface.
30 */
31 tpm_private_key_t public;
32
33 /**
34 * Token keyid used to reference optional PIN for TPM key
35 */
36 identification_t *keyid;
37
38 /**
39 * Trusted Platform Module
40 */
41 tpm_tss_t *tpm;
42
43 /**
44 * TPM key object handle
45 */
46 uint32_t handle;
47
48 /**
49 * Hierarchy the TPM key object is attached to
50 */
51 uint32_t hierarchy;
52
53 /**
54 * Associated public key
55 */
56 public_key_t *pubkey;
57
58 /**
59 * References to this key
60 */
61 refcount_t ref;
62
63 };
64
65
66 METHOD(private_key_t, get_type, key_type_t,
67 private_tpm_private_key_t *this)
68 {
69 return this->pubkey->get_type(this->pubkey);
70 }
71
72 METHOD(private_key_t, get_keysize, int,
73 private_tpm_private_key_t *this)
74 {
75 return this->pubkey->get_keysize(this->pubkey);
76 }
77
78 METHOD(private_key_t, sign, bool,
79 private_tpm_private_key_t *this, signature_scheme_t scheme,
80 chunk_t data, chunk_t *signature)
81 {
82 chunk_t pin = chunk_empty;
83 shared_key_t *shared;
84 enumerator_t *enumerator;
85
86 /* check for optional PIN */
87 enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr,
88 SHARED_PIN, this->keyid, NULL);
89 if (enumerator->enumerate(enumerator, &shared, NULL, NULL))
90 {
91 pin = shared->get_key(shared);
92 }
93 enumerator->destroy(enumerator);
94
95 return this->tpm->sign(this->tpm, this->hierarchy, this->handle, scheme,
96 data, pin, signature);
97 }
98
99 METHOD(private_key_t, decrypt, bool,
100 private_tpm_private_key_t *this, encryption_scheme_t scheme,
101 chunk_t crypt, chunk_t *plain)
102 {
103 return FALSE;
104 }
105
106 METHOD(private_key_t, get_public_key, public_key_t*,
107 private_tpm_private_key_t *this)
108 {
109 return this->pubkey->get_ref(this->pubkey);
110 }
111
112 METHOD(private_key_t, get_fingerprint, bool,
113 private_tpm_private_key_t *this, cred_encoding_type_t type,
114 chunk_t *fingerprint)
115 {
116 return this->pubkey->get_fingerprint(this->pubkey, type, fingerprint);
117 }
118
119 METHOD(private_key_t, get_encoding, bool,
120 private_tpm_private_key_t *this, cred_encoding_type_t type,
121 chunk_t *encoding)
122 {
123 return FALSE;
124 }
125
126 METHOD(private_key_t, get_ref, private_key_t*,
127 private_tpm_private_key_t *this)
128 {
129 ref_get(&this->ref);
130 return &this->public.key;
131 }
132
133 METHOD(private_key_t, destroy, void,
134 private_tpm_private_key_t *this)
135 {
136 if (ref_put(&this->ref))
137 {
138 DESTROY_IF(this->pubkey);
139 this->tpm->destroy(this->tpm);
140 this->keyid->destroy(this->keyid);
141 free(this);
142 }
143 }
144
145 /**
146 * See header.
147 */
148 tpm_private_key_t *tpm_private_key_connect(key_type_t type, va_list args)
149 {
150 private_tpm_private_key_t *this;
151 tpm_tss_t *tpm;
152 chunk_t keyid = chunk_empty, pubkey_blob = chunk_empty;
153 char handle_str[4];
154 size_t len;
155 uint32_t hierarchy = 0x4000000B; /* TPM_RH_ENDORSEMENT */
156 uint32_t handle;
157
158 while (TRUE)
159 {
160 switch (va_arg(args, builder_part_t))
161 {
162 case BUILD_PKCS11_KEYID:
163 keyid = va_arg(args, chunk_t);
164 continue;
165 case BUILD_PKCS11_SLOT:
166 hierarchy = va_arg(args, int);
167 continue;
168 case BUILD_PKCS11_MODULE:
169 va_arg(args, char*);
170 continue;
171 case BUILD_END:
172 break;
173 default:
174 return NULL;
175 }
176 break;
177 }
178
179 /* convert keyid into 32 bit TPM key object handle */
180 if (!keyid.len)
181 {
182 return NULL;
183 }
184 len = min(keyid.len, 4);
185 memset(handle_str, 0x00, 4);
186 memcpy(handle_str + 4 - len, keyid.ptr + keyid.len - len, len);
187 handle = untoh32(handle_str);
188
189 /* try to find a TPM 2.0 */
190 tpm = tpm_tss_probe(TPM_VERSION_2_0);
191 if (!tpm)
192 {
193 DBG1(DBG_LIB, "no TPM 2.0 found");
194 return NULL;
195 }
196
197 INIT(this,
198 .public = {
199 .key = {
200 .get_type = _get_type,
201 .sign = _sign,
202 .decrypt = _decrypt,
203 .get_keysize = _get_keysize,
204 .get_public_key = _get_public_key,
205 .equals = private_key_equals,
206 .belongs_to = private_key_belongs_to,
207 .get_fingerprint = _get_fingerprint,
208 .has_fingerprint = private_key_has_fingerprint,
209 .get_encoding = _get_encoding,
210 .get_ref = _get_ref,
211 .destroy = _destroy,
212 },
213 },
214 .tpm = tpm,
215 .keyid = identification_create_from_encoding(ID_KEY_ID, keyid),
216 .handle = handle,
217 .hierarchy = hierarchy,
218 .ref = 1,
219 );
220
221 /* get public key from TPM */
222 pubkey_blob = tpm->get_public(tpm, handle);
223 if (!pubkey_blob.len)
224 {
225 destroy(this);
226 return NULL;
227 }
228 this->pubkey = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ANY,
229 BUILD_BLOB_ASN1_DER, pubkey_blob, BUILD_END);
230 chunk_free(&pubkey_blob);
231
232 if (!this->pubkey)
233 {
234 destroy(this);
235 return NULL;
236 }
237
238 return &this->public;
239 }