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