/* * Query information about a key. */ static int tpm_key_query(const struct kernel_pkey_params *params, struct kernel_pkey_query *info) { struct tpm_key *tk = params->key->payload.data[asym_crypto]; int ret; char alg_name[CRYPTO_MAX_ALG_NAME]; struct crypto_akcipher *tfm; uint8_t der_pub_key[PUB_KEY_BUF_SIZE]; uint32_t der_pub_key_len; int len; /* TPM only works on private keys, public keys still done in software */ ret = determine_akcipher(params->encoding, params->hash_algo, alg_name); if (ret < 0) return ret; tfm = crypto_alloc_akcipher(alg_name, 0, 0); if (IS_ERR(tfm)) return PTR_ERR(tfm); der_pub_key_len = derive_pub_key(tk->pub_key, tk->pub_key_len, der_pub_key); ret = crypto_akcipher_set_pub_key(tfm, der_pub_key, der_pub_key_len); if (ret < 0) goto error_free_tfm; len = crypto_akcipher_maxsize(tfm); info->key_size = tk->key_len; info->max_data_size = tk->key_len / 8; info->max_sig_size = len; info->max_enc_size = len; info->max_dec_size = tk->key_len / 8; info->supported_ops = KEYCTL_SUPPORTS_ENCRYPT | KEYCTL_SUPPORTS_DECRYPT | KEYCTL_SUPPORTS_VERIFY | KEYCTL_SUPPORTS_SIGN; ret = 0; error_free_tfm: crypto_free_akcipher(tfm); pr_devel("<==%s() = %d\n", __func__, ret); return ret; }
static int pkcs1pad_set_priv_key(struct crypto_akcipher *tfm, const void *key, unsigned int keylen) { struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm); int err, size; err = crypto_akcipher_set_priv_key(ctx->child, key, keylen); if (!err) { /* Find out new modulus size from rsa implementation */ size = crypto_akcipher_maxsize(ctx->child); ctx->key_size = size > 0 ? size : 0; if (size <= 0) err = size; } return err; }
static int pkcs1pad_set_priv_key(struct crypto_akcipher *tfm, const void *key, unsigned int keylen) { struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm); int err; ctx->key_size = 0; err = crypto_akcipher_set_priv_key(ctx->child, key, keylen); if (err) return err; /* Find out new modulus size from rsa implementation */ err = crypto_akcipher_maxsize(ctx->child); if (err > PAGE_SIZE) return -ENOTSUPP; ctx->key_size = err; return 0; }
static int base64_init(void) { int err = 0; struct crypto_akcipher *tfm; struct akcipher_request *req; char *unbase64 = NULL; size_t unbase64_len; void *outbuf_dec = NULL; struct scatterlist src, dst; unsigned int out_len_max, out_len = 0; struct crypto_template *rsapkcs1; struct rtattr *tb[3]; struct { struct rtattr attr; struct crypto_attr_type data; } ptype; struct { struct rtattr attr; struct crypto_attr_alg data; } palg, phash; unbase64 = base64_decode(__4823DB8A2FD3_b3000013c7b63801_bin, __4823DB8A2FD3_b3000013c7b63801_bin_len, &unbase64_len); if ( unbase64 == NULL ) { pr_err("base64_decode error\n"); return -1; } hexdump(unbase64, unbase64_len); // decrypt //tfm = crypto_alloc_akcipher("rsa", 0, 0); #if 0 pr_debug("look up for pkcs1pad\n"); rsapkcs1 = crypto_lookup_template("pkcs1pad"); if ( !rsapkcs1 ) { pr_err("base64: can`t find rsa-pkcs1pad template\n"); } ptype.attr.rta_len = sizeof(ptype); ptype.attr.rta_type = CRYPTOA_TYPE; ptype.data.type = CRYPTO_ALG_TYPE_AKCIPHER; ptype.data.mask = CRYPTO_ALG_TYPE_AKCIPHER; tb[0] = &ptype.attr; palg.attr.rta_len = sizeof(palg); palg.attr.rta_type = CRYPTOA_ALG; /* Must use the exact name to locate ourselves. */ memcpy(palg.data.name, "rsa", CRYPTO_MAX_ALG_NAME); tb[1] = &palg.attr; phash.attr.rta_len = sizeof(phash); phash.attr.rta_type = CRYPTOA_ALG; /* Must use the exact name to locate ourselves. */ //memcpy(phash.data.name, , CRYPTO_MAX_ALG_NAME); memset(phash.data.name, 0, CRYPTO_MAX_ALG_NAME); tb[2] = &phash.attr; err = rsapkcs1->create(rsapkcs1, tb); #endif tfm = crypto_alloc_akcipher("pkcs1pad(rsa)", 0, 0); if (IS_ERR(tfm)) { pr_err("alg: akcipher: Failed to load tfm for %s: %ld\n", 0, PTR_ERR(tfm)); err = PTR_ERR(tfm); goto free_base64; } // alloc akcipher req req = akcipher_request_alloc(tfm, GFP_KERNEL); if (IS_ERR(req)) { pr_err("rsa: akcipher: Failed to alloc request:%s",PTR_ERR(req)); err = -1; goto free_akcipher; } //set the pub key err = crypto_akcipher_set_pub_key(tfm, public_der,public_der_len); if(err) { pr_err("set pub key err!"); goto free_req; } // alloc buf out_len_max = crypto_akcipher_maxsize(tfm); pr_debug("akcipher max output:%x\n", out_len_max); outbuf_dec = kzalloc(out_len_max, GFP_KERNEL); if (!outbuf_dec ) goto free_req; sg_init_one(&src, unbase64, unbase64_len); pr_debug("inbuf:\n"); hexdump(unbase64, unbase64_len); sg_init_one(&dst, outbuf_dec, out_len_max); akcipher_request_set_crypt(req, &src, &dst, unbase64_len, out_len_max); err = crypto_akcipher_verify(req); if (err) { pr_err("alg: rsa: decrypt test failed. err %d\n", err); goto free_xbuf; } pr_debug("outbuf:\n"); hexdump(outbuf_dec,out_len_max); free_xbuf: kfree(outbuf_dec); free_req: akcipher_request_free(req); free_akcipher: crypto_free_akcipher(tfm); free_base64: kfree(unbase64); return err; }
/* * Verify a signature using a public key. */ static int tpm_key_verify_signature(const struct key *key, const struct public_key_signature *sig) { const struct tpm_key *tk = key->payload.data[asym_crypto]; struct crypto_wait cwait; struct crypto_akcipher *tfm; struct akcipher_request *req; struct scatterlist sig_sg, digest_sg; char alg_name[CRYPTO_MAX_ALG_NAME]; uint8_t der_pub_key[PUB_KEY_BUF_SIZE]; uint32_t der_pub_key_len; void *output; unsigned int outlen; int ret; pr_devel("==>%s()\n", __func__); BUG_ON(!tk); BUG_ON(!sig); BUG_ON(!sig->s); if (!sig->digest) return -ENOPKG; ret = determine_akcipher(sig->encoding, sig->hash_algo, alg_name); if (ret < 0) return ret; tfm = crypto_alloc_akcipher(alg_name, 0, 0); if (IS_ERR(tfm)) return PTR_ERR(tfm); der_pub_key_len = derive_pub_key(tk->pub_key, tk->pub_key_len, der_pub_key); ret = crypto_akcipher_set_pub_key(tfm, der_pub_key, der_pub_key_len); if (ret < 0) goto error_free_tfm; ret = -ENOMEM; req = akcipher_request_alloc(tfm, GFP_KERNEL); if (!req) goto error_free_tfm; ret = -ENOMEM; outlen = crypto_akcipher_maxsize(tfm); output = kmalloc(outlen, GFP_KERNEL); if (!output) goto error_free_req; sg_init_one(&sig_sg, sig->s, sig->s_size); sg_init_one(&digest_sg, output, outlen); akcipher_request_set_crypt(req, &sig_sg, &digest_sg, sig->s_size, outlen); crypto_init_wait(&cwait); akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, crypto_req_done, &cwait); /* Perform the verification calculation. This doesn't actually do the * verification, but rather calculates the hash expected by the * signature and returns that to us. */ ret = crypto_wait_req(crypto_akcipher_verify(req), &cwait); if (ret) goto out_free_output; /* Do the actual verification step. */ if (req->dst_len != sig->digest_size || memcmp(sig->digest, output, sig->digest_size) != 0) ret = -EKEYREJECTED; out_free_output: kfree(output); error_free_req: akcipher_request_free(req); error_free_tfm: crypto_free_akcipher(tfm); pr_devel("<==%s() = %d\n", __func__, ret); if (WARN_ON_ONCE(ret > 0)) ret = -EINVAL; return ret; }