1 /*
2 * Copyright (c) 2018, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions 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 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /**
30 * @file
31 * This file implements ECDSA signing.
32 */
33
34 #include "ecdsa.hpp"
35
36 #if OPENTHREAD_CONFIG_ECDSA_ENABLE
37
38 #include <string.h>
39
40 #include <mbedtls/ctr_drbg.h>
41 #include <mbedtls/ecdsa.h>
42 #include <mbedtls/pk.h>
43 #include <mbedtls/version.h>
44
45 #include "common/code_utils.hpp"
46 #include "common/debug.hpp"
47 #include "common/random.hpp"
48 #include "crypto/mbedtls.hpp"
49
50 namespace ot {
51 namespace Crypto {
52 namespace Ecdsa {
53
Generate(void)54 Error P256::KeyPair::Generate(void)
55 {
56 mbedtls_pk_context pk;
57 int ret;
58
59 mbedtls_pk_init(&pk);
60
61 ret = mbedtls_pk_setup(&pk, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY));
62 VerifyOrExit(ret == 0);
63
64 ret = mbedtls_ecp_gen_key(MBEDTLS_ECP_DP_SECP256R1, mbedtls_pk_ec(pk), mbedtls_ctr_drbg_random,
65 Random::Crypto::MbedTlsContextGet());
66 VerifyOrExit(ret == 0);
67
68 ret = mbedtls_pk_write_key_der(&pk, mDerBytes, sizeof(mDerBytes));
69 VerifyOrExit(ret > 0);
70
71 mDerLength = static_cast<uint8_t>(ret);
72
73 memmove(mDerBytes, mDerBytes + sizeof(mDerBytes) - mDerLength, mDerLength);
74
75 exit:
76 mbedtls_pk_free(&pk);
77
78 return (ret >= 0) ? kErrorNone : MbedTls::MapError(ret);
79 }
80
Parse(void * aContext) const81 Error P256::KeyPair::Parse(void *aContext) const
82 {
83 Error error = kErrorNone;
84 mbedtls_pk_context *pk = reinterpret_cast<mbedtls_pk_context *>(aContext);
85
86 mbedtls_pk_init(pk);
87
88 VerifyOrExit(mbedtls_pk_setup(pk, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY)) == 0, error = kErrorFailed);
89 VerifyOrExit(mbedtls_pk_parse_key(pk, mDerBytes, mDerLength, nullptr, 0) == 0, error = kErrorParse);
90
91 exit:
92 return error;
93 }
94
GetPublicKey(PublicKey & aPublicKey) const95 Error P256::KeyPair::GetPublicKey(PublicKey &aPublicKey) const
96 {
97 Error error;
98 mbedtls_pk_context pk;
99 mbedtls_ecp_keypair *keyPair;
100 int ret;
101
102 SuccessOrExit(error = Parse(&pk));
103
104 keyPair = mbedtls_pk_ec(pk);
105
106 ret = mbedtls_mpi_write_binary(&keyPair->Q.X, aPublicKey.mData, kMpiSize);
107 VerifyOrExit(ret == 0, error = MbedTls::MapError(ret));
108
109 ret = mbedtls_mpi_write_binary(&keyPair->Q.Y, aPublicKey.mData + kMpiSize, kMpiSize);
110 VerifyOrExit(ret == 0, error = MbedTls::MapError(ret));
111
112 exit:
113 mbedtls_pk_free(&pk);
114 return error;
115 }
116
Sign(const Sha256::Hash & aHash,Signature & aSignature) const117 Error P256::KeyPair::Sign(const Sha256::Hash &aHash, Signature &aSignature) const
118 {
119 Error error;
120 mbedtls_pk_context pk;
121 mbedtls_ecp_keypair * keypair;
122 mbedtls_ecdsa_context ecdsa;
123 mbedtls_mpi r;
124 mbedtls_mpi s;
125 int ret;
126
127 mbedtls_ecdsa_init(&ecdsa);
128 mbedtls_mpi_init(&r);
129 mbedtls_mpi_init(&s);
130
131 SuccessOrExit(error = Parse(&pk));
132
133 keypair = mbedtls_pk_ec(pk);
134
135 ret = mbedtls_ecdsa_from_keypair(&ecdsa, keypair);
136 VerifyOrExit(ret == 0, error = MbedTls::MapError(ret));
137
138 #if (MBEDTLS_VERSION_NUMBER >= 0x02130000)
139 ret = mbedtls_ecdsa_sign_det_ext(&ecdsa.grp, &r, &s, &ecdsa.d, aHash.GetBytes(), Sha256::Hash::kSize,
140 MBEDTLS_MD_SHA256, mbedtls_ctr_drbg_random, Random::Crypto::MbedTlsContextGet());
141 #else
142 ret =
143 mbedtls_ecdsa_sign_det(&ecdsa.grp, &r, &s, &ecdsa.d, aHash.GetBytes(), Sha256::Hash::kSize, MBEDTLS_MD_SHA256);
144 #endif
145 VerifyOrExit(ret == 0, error = MbedTls::MapError(ret));
146
147 OT_ASSERT(mbedtls_mpi_size(&r) <= kMpiSize);
148
149 ret = mbedtls_mpi_write_binary(&r, aSignature.mShared.mMpis.mR, kMpiSize);
150 VerifyOrExit(ret == 0, error = MbedTls::MapError(ret));
151
152 ret = mbedtls_mpi_write_binary(&s, aSignature.mShared.mMpis.mS, kMpiSize);
153 VerifyOrExit(ret == 0, error = MbedTls::MapError(ret));
154
155 exit:
156 mbedtls_pk_free(&pk);
157 mbedtls_mpi_free(&s);
158 mbedtls_mpi_free(&r);
159 mbedtls_ecdsa_free(&ecdsa);
160
161 return error;
162 }
163
Verify(const Sha256::Hash & aHash,const Signature & aSignature) const164 Error P256::PublicKey::Verify(const Sha256::Hash &aHash, const Signature &aSignature) const
165 {
166 Error error = kErrorNone;
167 mbedtls_ecdsa_context ecdsa;
168 mbedtls_mpi r;
169 mbedtls_mpi s;
170 int ret;
171
172 mbedtls_ecdsa_init(&ecdsa);
173 mbedtls_mpi_init(&r);
174 mbedtls_mpi_init(&s);
175
176 ret = mbedtls_ecp_group_load(&ecdsa.grp, MBEDTLS_ECP_DP_SECP256R1);
177 VerifyOrExit(ret == 0, error = MbedTls::MapError(ret));
178
179 ret = mbedtls_mpi_read_binary(&ecdsa.Q.X, GetBytes(), kMpiSize);
180 VerifyOrExit(ret == 0, error = MbedTls::MapError(ret));
181 ret = mbedtls_mpi_read_binary(&ecdsa.Q.Y, GetBytes() + kMpiSize, kMpiSize);
182 VerifyOrExit(ret == 0, error = MbedTls::MapError(ret));
183 ret = mbedtls_mpi_lset(&ecdsa.Q.Z, 1);
184 VerifyOrExit(ret == 0, error = MbedTls::MapError(ret));
185
186 ret = mbedtls_mpi_read_binary(&r, aSignature.mShared.mMpis.mR, kMpiSize);
187 VerifyOrExit(ret == 0, error = MbedTls::MapError(ret));
188
189 ret = mbedtls_mpi_read_binary(&s, aSignature.mShared.mMpis.mS, kMpiSize);
190 VerifyOrExit(ret == 0, error = MbedTls::MapError(ret));
191
192 ret = mbedtls_ecdsa_verify(&ecdsa.grp, aHash.GetBytes(), Sha256::Hash::kSize, &ecdsa.Q, &r, &s);
193 VerifyOrExit(ret == 0, error = kErrorSecurity);
194
195 exit:
196 mbedtls_mpi_free(&s);
197 mbedtls_mpi_free(&r);
198 mbedtls_ecdsa_free(&ecdsa);
199
200 return error;
201 }
202
Sign(uint8_t * aOutput,uint16_t & aOutputLength,const uint8_t * aInputHash,uint16_t aInputHashLength,const uint8_t * aPrivateKey,uint16_t aPrivateKeyLength)203 Error Sign(uint8_t * aOutput,
204 uint16_t & aOutputLength,
205 const uint8_t *aInputHash,
206 uint16_t aInputHashLength,
207 const uint8_t *aPrivateKey,
208 uint16_t aPrivateKeyLength)
209 {
210 Error error = kErrorNone;
211 mbedtls_ecdsa_context ctx;
212 mbedtls_pk_context pkCtx;
213 mbedtls_ecp_keypair * keypair;
214 mbedtls_mpi rMpi;
215 mbedtls_mpi sMpi;
216
217 mbedtls_pk_init(&pkCtx);
218 mbedtls_ecdsa_init(&ctx);
219 mbedtls_mpi_init(&rMpi);
220 mbedtls_mpi_init(&sMpi);
221
222 // Parse a private key in PEM format.
223 VerifyOrExit(mbedtls_pk_parse_key(&pkCtx, aPrivateKey, aPrivateKeyLength, nullptr, 0) == 0,
224 error = kErrorInvalidArgs);
225 VerifyOrExit(mbedtls_pk_get_type(&pkCtx) == MBEDTLS_PK_ECKEY, error = kErrorInvalidArgs);
226
227 keypair = mbedtls_pk_ec(pkCtx);
228 OT_ASSERT(keypair != nullptr);
229
230 VerifyOrExit(mbedtls_ecdsa_from_keypair(&ctx, keypair) == 0, error = kErrorFailed);
231
232 // Sign using ECDSA.
233 VerifyOrExit(mbedtls_ecdsa_sign(&ctx.grp, &rMpi, &sMpi, &ctx.d, aInputHash, aInputHashLength,
234 mbedtls_ctr_drbg_random, Random::Crypto::MbedTlsContextGet()) == 0,
235 error = kErrorFailed);
236 VerifyOrExit(mbedtls_mpi_size(&rMpi) + mbedtls_mpi_size(&sMpi) <= aOutputLength, error = kErrorNoBufs);
237
238 // Concatenate the two octet sequences in the order R and then S.
239 VerifyOrExit(mbedtls_mpi_write_binary(&rMpi, aOutput, mbedtls_mpi_size(&rMpi)) == 0, error = kErrorFailed);
240 aOutputLength = static_cast<uint16_t>(mbedtls_mpi_size(&rMpi));
241
242 VerifyOrExit(mbedtls_mpi_write_binary(&sMpi, aOutput + aOutputLength, mbedtls_mpi_size(&sMpi)) == 0,
243 error = kErrorFailed);
244 aOutputLength += mbedtls_mpi_size(&sMpi);
245
246 exit:
247 mbedtls_mpi_free(&rMpi);
248 mbedtls_mpi_free(&sMpi);
249 mbedtls_ecdsa_free(&ctx);
250 mbedtls_pk_free(&pkCtx);
251
252 return error;
253 }
254
255 } // namespace Ecdsa
256 } // namespace Crypto
257 } // namespace ot
258
259 #endif // OPENTHREAD_CONFIG_ECDSA_ENABLE
260