summaryrefslogtreecommitdiffstats
path: root/crypto/asymmetric_keys/signature.c
blob: ad95a58c664275a9d561548fa79e6a027a74db0c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/* Signature verification with an asymmetric key
 *
 * See Documentation/crypto/asymmetric-keys.txt
 *
 * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
 * Written by David Howells (dhowells@redhat.com)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public Licence
 * as published by the Free Software Foundation; either version
 * 2 of the Licence, or (at your option) any later version.
 */

#define pr_fmt(fmt) "SIG: "fmt
#include <keys/asymmetric-subtype.h>
#include <linux/export.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/keyctl.h>
#include <crypto/public_key.h>
#include <keys/user-type.h>
#include "asymmetric_keys.h"

/*
 * Destroy a public key signature.
 */
void public_key_signature_free(struct public_key_signature *sig)
{
	int i;

	if (sig) {
		for (i = 0; i < ARRAY_SIZE(sig->auth_ids); i++)
			kfree(sig->auth_ids[i]);
		kfree(sig->s);
		kfree(sig->digest);
		kfree(sig);
	}
}
EXPORT_SYMBOL_GPL(public_key_signature_free);

/**
 * query_asymmetric_key - Get information about an aymmetric key.
 * @params: Various parameters.
 * @info: Where to put the information.
 */
int query_asymmetric_key(const struct kernel_pkey_params *params,
			 struct kernel_pkey_query *info)
{
	const struct asymmetric_key_subtype *subtype;
	struct key *key = params->key;
	int ret;

	pr_devel("==>%s()\n", __func__);

	if (key->type != &key_type_asymmetric)
		return -EINVAL;
	subtype = asymmetric_key_subtype(key);
	if (!subtype ||
	    !key->payload.data[0])
		return -EINVAL;
	if (!subtype->query)
		return -ENOTSUPP;

	ret = subtype->query(params, info);

	pr_devel("<==%s() = %d\n", __func__, ret);
	return ret;
}
EXPORT_SYMBOL_GPL(query_asymmetric_key);

/**
 * encrypt_blob - Encrypt data using an asymmetric key
 * @params: Various parameters
 * @data: Data blob to be encrypted, length params->data_len
 * @enc: Encrypted data buffer, length params->enc_len
 *
 * Encrypt the specified data blob using the private key specified by
 * params->key.  The encrypted data is wrapped in an encoding if
 * params->encoding is specified (eg. "pkcs1").
 *
 * Returns the length of the data placed in the encrypted data buffer or an
 * error.
 */
int encrypt_blob(struct kernel_pkey_params *params,
		 const void *data, void *enc)
{
	params->op = kernel_pkey_encrypt;
	return asymmetric_key_eds_op(params, data, enc);
}
EXPORT_SYMBOL_GPL(encrypt_blob);

/**
 * decrypt_blob - Decrypt data using an asymmetric key
 * @params: Various parameters
 * @enc: Encrypted data to be decrypted, length params->enc_len
 * @data: Decrypted data buffer, length params->data_len
 *
 * Decrypt the specified data blob using the private key specified by
 * params->key.  The decrypted data is wrapped in an encoding if
 * params->encoding is specified (eg. "pkcs1").
 *
 * Returns the length of the data placed in the decrypted data buffer or an
 * error.
 */
int decrypt_blob(struct kernel_pkey_params *params,
		 const void *enc, void *data)
{
	params->op = kernel_pkey_decrypt;
	return asymmetric_key_eds_op(params, enc, data);
}
EXPORT_SYMBOL_GPL(decrypt_blob);

/**
 * create_signature - Sign some data using an asymmetric key
 * @params: Various parameters
 * @data: Data blob to be signed, length params->data_len
 * @enc: Signature buffer, length params->enc_len
 *
 * Sign the specified data blob using the private key specified by params->key.
 * The signature is wrapped in an encoding if params->encoding is specified
 * (eg. "pkcs1").  If the encoding needs to know the digest type, this can be
 * passed through params->hash_algo (eg. "sha1").
 *
 * Returns the length of the data placed in the signature buffer or an error.
 */
int create_signature(struct kernel_pkey_params *params,
		     const void *data, void *enc)
{
	params->op = kernel_pkey_sign;
	return asymmetric_key_eds_op(params, data, enc);
}
EXPORT_SYMBOL_GPL(create_signature);

/**
 * verify_signature - Initiate the use of an asymmetric key to verify a signature
 * @key: The asymmetric key to verify against
 * @sig: The signature to check
 *
 * Returns 0 if successful or else an error.
 */
int verify_signature(const struct key *key,
		     const struct public_key_signature *sig)
{
	const struct asymmetric_key_subtype *subtype;
	int ret;

	pr_devel("==>%s()\n", __func__);

	if (key->type != &key_type_asymmetric)
		return -EINVAL;
	subtype = asymmetric_key_subtype(key);
	if (!subtype ||
	    !key->payload.data[0])
		return -EINVAL;
	if (!subtype->verify_signature)
		return -ENOTSUPP;

	ret = subtype->verify_signature(key, sig);

	pr_devel("<==%s() = %d\n", __func__, ret);
	return ret;
}
EXPORT_SYMBOL_GPL(verify_signature);