summaryrefslogtreecommitdiffstats
path: root/crypto/asymmetric_keys
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/asymmetric_keys')
-rw-r--r--crypto/asymmetric_keys/asym_tpm.c87
1 files changed, 87 insertions, 0 deletions
diff --git a/crypto/asymmetric_keys/asym_tpm.c b/crypto/asymmetric_keys/asym_tpm.c
index a38ba375675e..a5a5f913a74f 100644
--- a/crypto/asymmetric_keys/asym_tpm.c
+++ b/crypto/asymmetric_keys/asym_tpm.c
@@ -20,9 +20,11 @@
20#define TPM_ORD_FLUSHSPECIFIC 186 20#define TPM_ORD_FLUSHSPECIFIC 186
21#define TPM_ORD_LOADKEY2 65 21#define TPM_ORD_LOADKEY2 65
22#define TPM_ORD_UNBIND 30 22#define TPM_ORD_UNBIND 30
23#define TPM_ORD_SIGN 60
23#define TPM_LOADKEY2_SIZE 59 24#define TPM_LOADKEY2_SIZE 59
24#define TPM_FLUSHSPECIFIC_SIZE 18 25#define TPM_FLUSHSPECIFIC_SIZE 18
25#define TPM_UNBIND_SIZE 63 26#define TPM_UNBIND_SIZE 63
27#define TPM_SIGN_SIZE 63
26 28
27#define TPM_RT_KEY 0x00000001 29#define TPM_RT_KEY 0x00000001
28 30
@@ -190,6 +192,91 @@ static int tpm_unbind(struct tpm_buf *tb,
190} 192}
191 193
192/* 194/*
195 * Sign a blob provided by userspace (that has had the hash function applied)
196 * using a specific key handle. The handle is assumed to have been previously
197 * loaded by e.g. LoadKey2.
198 *
199 * Note that the key signature scheme of the used key should be set to
200 * TPM_SS_RSASSAPKCS1v15_DER. This allows the hashed input to be of any size
201 * up to key_length_in_bytes - 11 and not be limited to size 20 like the
202 * TPM_SS_RSASSAPKCS1v15_SHA1 signature scheme.
203 */
204static int tpm_sign(struct tpm_buf *tb,
205 uint32_t keyhandle, unsigned char *keyauth,
206 const unsigned char *blob, uint32_t bloblen,
207 void *out, uint32_t outlen)
208{
209 unsigned char nonceodd[TPM_NONCE_SIZE];
210 unsigned char enonce[TPM_NONCE_SIZE];
211 unsigned char authdata[SHA1_DIGEST_SIZE];
212 uint32_t authhandle = 0;
213 unsigned char cont = 0;
214 uint32_t ordinal;
215 uint32_t datalen;
216 int ret;
217
218 ordinal = htonl(TPM_ORD_SIGN);
219 datalen = htonl(bloblen);
220
221 /* session for loading the key */
222 ret = oiap(tb, &authhandle, enonce);
223 if (ret < 0) {
224 pr_info("oiap failed (%d)\n", ret);
225 return ret;
226 }
227
228 /* generate odd nonce */
229 ret = tpm_get_random(NULL, nonceodd, TPM_NONCE_SIZE);
230 if (ret < 0) {
231 pr_info("tpm_get_random failed (%d)\n", ret);
232 return ret;
233 }
234
235 /* calculate authorization HMAC value */
236 ret = TSS_authhmac(authdata, keyauth, SHA1_DIGEST_SIZE, enonce,
237 nonceodd, cont, sizeof(uint32_t), &ordinal,
238 sizeof(uint32_t), &datalen,
239 bloblen, blob, 0, 0);
240 if (ret < 0)
241 return ret;
242
243 /* build the request buffer */
244 INIT_BUF(tb);
245 store16(tb, TPM_TAG_RQU_AUTH1_COMMAND);
246 store32(tb, TPM_SIGN_SIZE + bloblen);
247 store32(tb, TPM_ORD_SIGN);
248 store32(tb, keyhandle);
249 store32(tb, bloblen);
250 storebytes(tb, blob, bloblen);
251 store32(tb, authhandle);
252 storebytes(tb, nonceodd, TPM_NONCE_SIZE);
253 store8(tb, cont);
254 storebytes(tb, authdata, SHA1_DIGEST_SIZE);
255
256 ret = trusted_tpm_send(tb->data, MAX_BUF_SIZE);
257 if (ret < 0) {
258 pr_info("authhmac failed (%d)\n", ret);
259 return ret;
260 }
261
262 datalen = LOAD32(tb->data, TPM_DATA_OFFSET);
263
264 ret = TSS_checkhmac1(tb->data, ordinal, nonceodd,
265 keyauth, SHA1_DIGEST_SIZE,
266 sizeof(uint32_t), TPM_DATA_OFFSET,
267 datalen, TPM_DATA_OFFSET + sizeof(uint32_t),
268 0, 0);
269 if (ret < 0) {
270 pr_info("TSS_checkhmac1 failed (%d)\n", ret);
271 return ret;
272 }
273
274 memcpy(out, tb->data + TPM_DATA_OFFSET + sizeof(uint32_t),
275 min(datalen, outlen));
276
277 return datalen;
278}
279/*
193 * Maximum buffer size for the BER/DER encoded public key. The public key 280 * Maximum buffer size for the BER/DER encoded public key. The public key
194 * is of the form SEQUENCE { INTEGER n, INTEGER e } where n is a maximum 2048 281 * is of the form SEQUENCE { INTEGER n, INTEGER e } where n is a maximum 2048
195 * bit key and e is usually 65537 282 * bit key and e is usually 65537