xref: /optee_os/lib/libmbedtls/mbedtls/library/ecdsa.c (revision c6672fdcd95b9a895eb5b4191f8ba3483a34a442)
1*c6672fdcSEdison Ai // SPDX-License-Identifier: Apache-2.0
2817466cbSJens Wiklander /*
3817466cbSJens Wiklander  *  Elliptic curve DSA
4817466cbSJens Wiklander  *
5817466cbSJens Wiklander  *  Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
6817466cbSJens Wiklander  *
7817466cbSJens Wiklander  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
8817466cbSJens Wiklander  *  not use this file except in compliance with the License.
9817466cbSJens Wiklander  *  You may obtain a copy of the License at
10817466cbSJens Wiklander  *
11817466cbSJens Wiklander  *  http://www.apache.org/licenses/LICENSE-2.0
12817466cbSJens Wiklander  *
13817466cbSJens Wiklander  *  Unless required by applicable law or agreed to in writing, software
14817466cbSJens Wiklander  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15817466cbSJens Wiklander  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16817466cbSJens Wiklander  *  See the License for the specific language governing permissions and
17817466cbSJens Wiklander  *  limitations under the License.
18817466cbSJens Wiklander  *
19817466cbSJens Wiklander  *  This file is part of mbed TLS (https://tls.mbed.org)
20817466cbSJens Wiklander  */
21817466cbSJens Wiklander 
22817466cbSJens Wiklander /*
23817466cbSJens Wiklander  * References:
24817466cbSJens Wiklander  *
25817466cbSJens Wiklander  * SEC1 http://www.secg.org/index.php?action=secg,docs_secg
26817466cbSJens Wiklander  */
27817466cbSJens Wiklander 
28817466cbSJens Wiklander #if !defined(MBEDTLS_CONFIG_FILE)
29817466cbSJens Wiklander #include "mbedtls/config.h"
30817466cbSJens Wiklander #else
31817466cbSJens Wiklander #include MBEDTLS_CONFIG_FILE
32817466cbSJens Wiklander #endif
33817466cbSJens Wiklander 
34817466cbSJens Wiklander #if defined(MBEDTLS_ECDSA_C)
35817466cbSJens Wiklander 
36817466cbSJens Wiklander #include "mbedtls/ecdsa.h"
37817466cbSJens Wiklander #include "mbedtls/asn1write.h"
38817466cbSJens Wiklander 
39817466cbSJens Wiklander #include <string.h>
40817466cbSJens Wiklander 
41817466cbSJens Wiklander #if defined(MBEDTLS_ECDSA_DETERMINISTIC)
42817466cbSJens Wiklander #include "mbedtls/hmac_drbg.h"
43817466cbSJens Wiklander #endif
44817466cbSJens Wiklander 
45817466cbSJens Wiklander /*
46817466cbSJens Wiklander  * Derive a suitable integer for group grp from a buffer of length len
47817466cbSJens Wiklander  * SEC1 4.1.3 step 5 aka SEC1 4.1.4 step 3
48817466cbSJens Wiklander  */
49817466cbSJens Wiklander static int derive_mpi( const mbedtls_ecp_group *grp, mbedtls_mpi *x,
50817466cbSJens Wiklander                        const unsigned char *buf, size_t blen )
51817466cbSJens Wiklander {
52817466cbSJens Wiklander     int ret;
53817466cbSJens Wiklander     size_t n_size = ( grp->nbits + 7 ) / 8;
54817466cbSJens Wiklander     size_t use_size = blen > n_size ? n_size : blen;
55817466cbSJens Wiklander 
56817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( x, buf, use_size ) );
57817466cbSJens Wiklander     if( use_size * 8 > grp->nbits )
58817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( x, use_size * 8 - grp->nbits ) );
59817466cbSJens Wiklander 
60817466cbSJens Wiklander     /* While at it, reduce modulo N */
61817466cbSJens Wiklander     if( mbedtls_mpi_cmp_mpi( x, &grp->N ) >= 0 )
62817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( x, x, &grp->N ) );
63817466cbSJens Wiklander 
64817466cbSJens Wiklander cleanup:
65817466cbSJens Wiklander     return( ret );
66817466cbSJens Wiklander }
67817466cbSJens Wiklander 
68817466cbSJens Wiklander /*
69817466cbSJens Wiklander  * Compute ECDSA signature of a hashed message (SEC1 4.1.3)
70817466cbSJens Wiklander  * Obviously, compared to SEC1 4.1.3, we skip step 4 (hash message)
71817466cbSJens Wiklander  */
72817466cbSJens Wiklander int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s,
73817466cbSJens Wiklander                 const mbedtls_mpi *d, const unsigned char *buf, size_t blen,
74817466cbSJens Wiklander                 int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
75817466cbSJens Wiklander {
76817466cbSJens Wiklander     int ret, key_tries, sign_tries, blind_tries;
77817466cbSJens Wiklander     mbedtls_ecp_point R;
78817466cbSJens Wiklander     mbedtls_mpi k, e, t;
79817466cbSJens Wiklander 
80817466cbSJens Wiklander     /* Fail cleanly on curves such as Curve25519 that can't be used for ECDSA */
81817466cbSJens Wiklander     if( grp->N.p == NULL )
82817466cbSJens Wiklander         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
83817466cbSJens Wiklander 
84817466cbSJens Wiklander     mbedtls_ecp_point_init( &R );
85817466cbSJens Wiklander     mbedtls_mpi_init( &k ); mbedtls_mpi_init( &e ); mbedtls_mpi_init( &t );
86817466cbSJens Wiklander 
87817466cbSJens Wiklander     sign_tries = 0;
88817466cbSJens Wiklander     do
89817466cbSJens Wiklander     {
90817466cbSJens Wiklander         /*
91817466cbSJens Wiklander          * Steps 1-3: generate a suitable ephemeral keypair
92817466cbSJens Wiklander          * and set r = xR mod n
93817466cbSJens Wiklander          */
94817466cbSJens Wiklander         key_tries = 0;
95817466cbSJens Wiklander         do
96817466cbSJens Wiklander         {
97817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_ecp_gen_keypair( grp, &k, &R, f_rng, p_rng ) );
98817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( r, &R.X, &grp->N ) );
99817466cbSJens Wiklander 
100817466cbSJens Wiklander             if( key_tries++ > 10 )
101817466cbSJens Wiklander             {
102817466cbSJens Wiklander                 ret = MBEDTLS_ERR_ECP_RANDOM_FAILED;
103817466cbSJens Wiklander                 goto cleanup;
104817466cbSJens Wiklander             }
105817466cbSJens Wiklander         }
106817466cbSJens Wiklander         while( mbedtls_mpi_cmp_int( r, 0 ) == 0 );
107817466cbSJens Wiklander 
108817466cbSJens Wiklander         /*
109817466cbSJens Wiklander          * Step 5: derive MPI from hashed message
110817466cbSJens Wiklander          */
111817466cbSJens Wiklander         MBEDTLS_MPI_CHK( derive_mpi( grp, &e, buf, blen ) );
112817466cbSJens Wiklander 
113817466cbSJens Wiklander         /*
114817466cbSJens Wiklander          * Generate a random value to blind inv_mod in next step,
115817466cbSJens Wiklander          * avoiding a potential timing leak.
116817466cbSJens Wiklander          */
117817466cbSJens Wiklander         blind_tries = 0;
118817466cbSJens Wiklander         do
119817466cbSJens Wiklander         {
120817466cbSJens Wiklander             size_t n_size = ( grp->nbits + 7 ) / 8;
121817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &t, n_size, f_rng, p_rng ) );
122817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &t, 8 * n_size - grp->nbits ) );
123817466cbSJens Wiklander 
124817466cbSJens Wiklander             /* See mbedtls_ecp_gen_keypair() */
125817466cbSJens Wiklander             if( ++blind_tries > 30 )
126817466cbSJens Wiklander                 return( MBEDTLS_ERR_ECP_RANDOM_FAILED );
127817466cbSJens Wiklander         }
128817466cbSJens Wiklander         while( mbedtls_mpi_cmp_int( &t, 1 ) < 0 ||
129817466cbSJens Wiklander                mbedtls_mpi_cmp_mpi( &t, &grp->N ) >= 0 );
130817466cbSJens Wiklander 
131817466cbSJens Wiklander         /*
132817466cbSJens Wiklander          * Step 6: compute s = (e + r * d) / k = t (e + rd) / (kt) mod n
133817466cbSJens Wiklander          */
134817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( s, r, d ) );
135817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &e, &e, s ) );
136817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &e, &e, &t ) );
137817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &k, &k, &t ) );
138817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( s, &k, &grp->N ) );
139817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( s, s, &e ) );
140817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( s, s, &grp->N ) );
141817466cbSJens Wiklander 
142817466cbSJens Wiklander         if( sign_tries++ > 10 )
143817466cbSJens Wiklander         {
144817466cbSJens Wiklander             ret = MBEDTLS_ERR_ECP_RANDOM_FAILED;
145817466cbSJens Wiklander             goto cleanup;
146817466cbSJens Wiklander         }
147817466cbSJens Wiklander     }
148817466cbSJens Wiklander     while( mbedtls_mpi_cmp_int( s, 0 ) == 0 );
149817466cbSJens Wiklander 
150817466cbSJens Wiklander cleanup:
151817466cbSJens Wiklander     mbedtls_ecp_point_free( &R );
152817466cbSJens Wiklander     mbedtls_mpi_free( &k ); mbedtls_mpi_free( &e ); mbedtls_mpi_free( &t );
153817466cbSJens Wiklander 
154817466cbSJens Wiklander     return( ret );
155817466cbSJens Wiklander }
156817466cbSJens Wiklander 
157817466cbSJens Wiklander #if defined(MBEDTLS_ECDSA_DETERMINISTIC)
158817466cbSJens Wiklander /*
159817466cbSJens Wiklander  * Deterministic signature wrapper
160817466cbSJens Wiklander  */
161817466cbSJens Wiklander int mbedtls_ecdsa_sign_det( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s,
162817466cbSJens Wiklander                     const mbedtls_mpi *d, const unsigned char *buf, size_t blen,
163817466cbSJens Wiklander                     mbedtls_md_type_t md_alg )
164817466cbSJens Wiklander {
165817466cbSJens Wiklander     int ret;
166817466cbSJens Wiklander     mbedtls_hmac_drbg_context rng_ctx;
167817466cbSJens Wiklander     unsigned char data[2 * MBEDTLS_ECP_MAX_BYTES];
168817466cbSJens Wiklander     size_t grp_len = ( grp->nbits + 7 ) / 8;
169817466cbSJens Wiklander     const mbedtls_md_info_t *md_info;
170817466cbSJens Wiklander     mbedtls_mpi h;
171817466cbSJens Wiklander 
172817466cbSJens Wiklander     if( ( md_info = mbedtls_md_info_from_type( md_alg ) ) == NULL )
173817466cbSJens Wiklander         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
174817466cbSJens Wiklander 
175817466cbSJens Wiklander     mbedtls_mpi_init( &h );
176817466cbSJens Wiklander     mbedtls_hmac_drbg_init( &rng_ctx );
177817466cbSJens Wiklander 
178817466cbSJens Wiklander     /* Use private key and message hash (reduced) to initialize HMAC_DRBG */
179817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( d, data, grp_len ) );
180817466cbSJens Wiklander     MBEDTLS_MPI_CHK( derive_mpi( grp, &h, buf, blen ) );
181817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &h, data + grp_len, grp_len ) );
182817466cbSJens Wiklander     mbedtls_hmac_drbg_seed_buf( &rng_ctx, md_info, data, 2 * grp_len );
183817466cbSJens Wiklander 
184817466cbSJens Wiklander     ret = mbedtls_ecdsa_sign( grp, r, s, d, buf, blen,
185817466cbSJens Wiklander                       mbedtls_hmac_drbg_random, &rng_ctx );
186817466cbSJens Wiklander 
187817466cbSJens Wiklander cleanup:
188817466cbSJens Wiklander     mbedtls_hmac_drbg_free( &rng_ctx );
189817466cbSJens Wiklander     mbedtls_mpi_free( &h );
190817466cbSJens Wiklander 
191817466cbSJens Wiklander     return( ret );
192817466cbSJens Wiklander }
193817466cbSJens Wiklander #endif /* MBEDTLS_ECDSA_DETERMINISTIC */
194817466cbSJens Wiklander 
195817466cbSJens Wiklander /*
196817466cbSJens Wiklander  * Verify ECDSA signature of hashed message (SEC1 4.1.4)
197817466cbSJens Wiklander  * Obviously, compared to SEC1 4.1.3, we skip step 2 (hash message)
198817466cbSJens Wiklander  */
199817466cbSJens Wiklander int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp,
200817466cbSJens Wiklander                   const unsigned char *buf, size_t blen,
201817466cbSJens Wiklander                   const mbedtls_ecp_point *Q, const mbedtls_mpi *r, const mbedtls_mpi *s)
202817466cbSJens Wiklander {
203817466cbSJens Wiklander     int ret;
204817466cbSJens Wiklander     mbedtls_mpi e, s_inv, u1, u2;
205817466cbSJens Wiklander     mbedtls_ecp_point R;
206817466cbSJens Wiklander 
207817466cbSJens Wiklander     mbedtls_ecp_point_init( &R );
208817466cbSJens Wiklander     mbedtls_mpi_init( &e ); mbedtls_mpi_init( &s_inv ); mbedtls_mpi_init( &u1 ); mbedtls_mpi_init( &u2 );
209817466cbSJens Wiklander 
210817466cbSJens Wiklander     /* Fail cleanly on curves such as Curve25519 that can't be used for ECDSA */
211817466cbSJens Wiklander     if( grp->N.p == NULL )
212817466cbSJens Wiklander         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
213817466cbSJens Wiklander 
214817466cbSJens Wiklander     /*
215817466cbSJens Wiklander      * Step 1: make sure r and s are in range 1..n-1
216817466cbSJens Wiklander      */
217817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( r, 1 ) < 0 || mbedtls_mpi_cmp_mpi( r, &grp->N ) >= 0 ||
218817466cbSJens Wiklander         mbedtls_mpi_cmp_int( s, 1 ) < 0 || mbedtls_mpi_cmp_mpi( s, &grp->N ) >= 0 )
219817466cbSJens Wiklander     {
220817466cbSJens Wiklander         ret = MBEDTLS_ERR_ECP_VERIFY_FAILED;
221817466cbSJens Wiklander         goto cleanup;
222817466cbSJens Wiklander     }
223817466cbSJens Wiklander 
224817466cbSJens Wiklander     /*
225817466cbSJens Wiklander      * Additional precaution: make sure Q is valid
226817466cbSJens Wiklander      */
227817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_ecp_check_pubkey( grp, Q ) );
228817466cbSJens Wiklander 
229817466cbSJens Wiklander     /*
230817466cbSJens Wiklander      * Step 3: derive MPI from hashed message
231817466cbSJens Wiklander      */
232817466cbSJens Wiklander     MBEDTLS_MPI_CHK( derive_mpi( grp, &e, buf, blen ) );
233817466cbSJens Wiklander 
234817466cbSJens Wiklander     /*
235817466cbSJens Wiklander      * Step 4: u1 = e / s mod n, u2 = r / s mod n
236817466cbSJens Wiklander      */
237817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &s_inv, s, &grp->N ) );
238817466cbSJens Wiklander 
239817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &u1, &e, &s_inv ) );
240817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &u1, &u1, &grp->N ) );
241817466cbSJens Wiklander 
242817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &u2, r, &s_inv ) );
243817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &u2, &u2, &grp->N ) );
244817466cbSJens Wiklander 
245817466cbSJens Wiklander     /*
246817466cbSJens Wiklander      * Step 5: R = u1 G + u2 Q
247817466cbSJens Wiklander      *
248817466cbSJens Wiklander      * Since we're not using any secret data, no need to pass a RNG to
249817466cbSJens Wiklander      * mbedtls_ecp_mul() for countermesures.
250817466cbSJens Wiklander      */
251817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( grp, &R, &u1, &grp->G, &u2, Q ) );
252817466cbSJens Wiklander 
253817466cbSJens Wiklander     if( mbedtls_ecp_is_zero( &R ) )
254817466cbSJens Wiklander     {
255817466cbSJens Wiklander         ret = MBEDTLS_ERR_ECP_VERIFY_FAILED;
256817466cbSJens Wiklander         goto cleanup;
257817466cbSJens Wiklander     }
258817466cbSJens Wiklander 
259817466cbSJens Wiklander     /*
260817466cbSJens Wiklander      * Step 6: convert xR to an integer (no-op)
261817466cbSJens Wiklander      * Step 7: reduce xR mod n (gives v)
262817466cbSJens Wiklander      */
263817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &R.X, &R.X, &grp->N ) );
264817466cbSJens Wiklander 
265817466cbSJens Wiklander     /*
266817466cbSJens Wiklander      * Step 8: check if v (that is, R.X) is equal to r
267817466cbSJens Wiklander      */
268817466cbSJens Wiklander     if( mbedtls_mpi_cmp_mpi( &R.X, r ) != 0 )
269817466cbSJens Wiklander     {
270817466cbSJens Wiklander         ret = MBEDTLS_ERR_ECP_VERIFY_FAILED;
271817466cbSJens Wiklander         goto cleanup;
272817466cbSJens Wiklander     }
273817466cbSJens Wiklander 
274817466cbSJens Wiklander cleanup:
275817466cbSJens Wiklander     mbedtls_ecp_point_free( &R );
276817466cbSJens Wiklander     mbedtls_mpi_free( &e ); mbedtls_mpi_free( &s_inv ); mbedtls_mpi_free( &u1 ); mbedtls_mpi_free( &u2 );
277817466cbSJens Wiklander 
278817466cbSJens Wiklander     return( ret );
279817466cbSJens Wiklander }
280817466cbSJens Wiklander 
281817466cbSJens Wiklander /*
282817466cbSJens Wiklander  * Convert a signature (given by context) to ASN.1
283817466cbSJens Wiklander  */
284817466cbSJens Wiklander static int ecdsa_signature_to_asn1( const mbedtls_mpi *r, const mbedtls_mpi *s,
285817466cbSJens Wiklander                                     unsigned char *sig, size_t *slen )
286817466cbSJens Wiklander {
287817466cbSJens Wiklander     int ret;
288817466cbSJens Wiklander     unsigned char buf[MBEDTLS_ECDSA_MAX_LEN];
289817466cbSJens Wiklander     unsigned char *p = buf + sizeof( buf );
290817466cbSJens Wiklander     size_t len = 0;
291817466cbSJens Wiklander 
292817466cbSJens Wiklander     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &p, buf, s ) );
293817466cbSJens Wiklander     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &p, buf, r ) );
294817466cbSJens Wiklander 
295817466cbSJens Wiklander     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &p, buf, len ) );
296817466cbSJens Wiklander     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &p, buf,
297817466cbSJens Wiklander                                        MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) );
298817466cbSJens Wiklander 
299817466cbSJens Wiklander     memcpy( sig, p, len );
300817466cbSJens Wiklander     *slen = len;
301817466cbSJens Wiklander 
302817466cbSJens Wiklander     return( 0 );
303817466cbSJens Wiklander }
304817466cbSJens Wiklander 
305817466cbSJens Wiklander /*
306817466cbSJens Wiklander  * Compute and write signature
307817466cbSJens Wiklander  */
308817466cbSJens Wiklander int mbedtls_ecdsa_write_signature( mbedtls_ecdsa_context *ctx, mbedtls_md_type_t md_alg,
309817466cbSJens Wiklander                            const unsigned char *hash, size_t hlen,
310817466cbSJens Wiklander                            unsigned char *sig, size_t *slen,
311817466cbSJens Wiklander                            int (*f_rng)(void *, unsigned char *, size_t),
312817466cbSJens Wiklander                            void *p_rng )
313817466cbSJens Wiklander {
314817466cbSJens Wiklander     int ret;
315817466cbSJens Wiklander     mbedtls_mpi r, s;
316817466cbSJens Wiklander 
317817466cbSJens Wiklander     mbedtls_mpi_init( &r );
318817466cbSJens Wiklander     mbedtls_mpi_init( &s );
319817466cbSJens Wiklander 
320817466cbSJens Wiklander #if defined(MBEDTLS_ECDSA_DETERMINISTIC)
321817466cbSJens Wiklander     (void) f_rng;
322817466cbSJens Wiklander     (void) p_rng;
323817466cbSJens Wiklander 
324817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_ecdsa_sign_det( &ctx->grp, &r, &s, &ctx->d,
325817466cbSJens Wiklander                              hash, hlen, md_alg ) );
326817466cbSJens Wiklander #else
327817466cbSJens Wiklander     (void) md_alg;
328817466cbSJens Wiklander 
329817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_ecdsa_sign( &ctx->grp, &r, &s, &ctx->d,
330817466cbSJens Wiklander                          hash, hlen, f_rng, p_rng ) );
331817466cbSJens Wiklander #endif
332817466cbSJens Wiklander 
333817466cbSJens Wiklander     MBEDTLS_MPI_CHK( ecdsa_signature_to_asn1( &r, &s, sig, slen ) );
334817466cbSJens Wiklander 
335817466cbSJens Wiklander cleanup:
336817466cbSJens Wiklander     mbedtls_mpi_free( &r );
337817466cbSJens Wiklander     mbedtls_mpi_free( &s );
338817466cbSJens Wiklander 
339817466cbSJens Wiklander     return( ret );
340817466cbSJens Wiklander }
341817466cbSJens Wiklander 
342817466cbSJens Wiklander #if ! defined(MBEDTLS_DEPRECATED_REMOVED) && \
343817466cbSJens Wiklander     defined(MBEDTLS_ECDSA_DETERMINISTIC)
344817466cbSJens Wiklander int mbedtls_ecdsa_write_signature_det( mbedtls_ecdsa_context *ctx,
345817466cbSJens Wiklander                                const unsigned char *hash, size_t hlen,
346817466cbSJens Wiklander                                unsigned char *sig, size_t *slen,
347817466cbSJens Wiklander                                mbedtls_md_type_t md_alg )
348817466cbSJens Wiklander {
349817466cbSJens Wiklander     return( mbedtls_ecdsa_write_signature( ctx, md_alg, hash, hlen, sig, slen,
350817466cbSJens Wiklander                                    NULL, NULL ) );
351817466cbSJens Wiklander }
352817466cbSJens Wiklander #endif
353817466cbSJens Wiklander 
354817466cbSJens Wiklander /*
355817466cbSJens Wiklander  * Read and check signature
356817466cbSJens Wiklander  */
357817466cbSJens Wiklander int mbedtls_ecdsa_read_signature( mbedtls_ecdsa_context *ctx,
358817466cbSJens Wiklander                           const unsigned char *hash, size_t hlen,
359817466cbSJens Wiklander                           const unsigned char *sig, size_t slen )
360817466cbSJens Wiklander {
361817466cbSJens Wiklander     int ret;
362817466cbSJens Wiklander     unsigned char *p = (unsigned char *) sig;
363817466cbSJens Wiklander     const unsigned char *end = sig + slen;
364817466cbSJens Wiklander     size_t len;
365817466cbSJens Wiklander     mbedtls_mpi r, s;
366817466cbSJens Wiklander 
367817466cbSJens Wiklander     mbedtls_mpi_init( &r );
368817466cbSJens Wiklander     mbedtls_mpi_init( &s );
369817466cbSJens Wiklander 
370817466cbSJens Wiklander     if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
371817466cbSJens Wiklander                     MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
372817466cbSJens Wiklander     {
373817466cbSJens Wiklander         ret += MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
374817466cbSJens Wiklander         goto cleanup;
375817466cbSJens Wiklander     }
376817466cbSJens Wiklander 
377817466cbSJens Wiklander     if( p + len != end )
378817466cbSJens Wiklander     {
379817466cbSJens Wiklander         ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA +
380817466cbSJens Wiklander               MBEDTLS_ERR_ASN1_LENGTH_MISMATCH;
381817466cbSJens Wiklander         goto cleanup;
382817466cbSJens Wiklander     }
383817466cbSJens Wiklander 
384817466cbSJens Wiklander     if( ( ret = mbedtls_asn1_get_mpi( &p, end, &r ) ) != 0 ||
385817466cbSJens Wiklander         ( ret = mbedtls_asn1_get_mpi( &p, end, &s ) ) != 0 )
386817466cbSJens Wiklander     {
387817466cbSJens Wiklander         ret += MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
388817466cbSJens Wiklander         goto cleanup;
389817466cbSJens Wiklander     }
390817466cbSJens Wiklander 
391817466cbSJens Wiklander     if( ( ret = mbedtls_ecdsa_verify( &ctx->grp, hash, hlen,
392817466cbSJens Wiklander                               &ctx->Q, &r, &s ) ) != 0 )
393817466cbSJens Wiklander         goto cleanup;
394817466cbSJens Wiklander 
395817466cbSJens Wiklander     if( p != end )
396817466cbSJens Wiklander         ret = MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH;
397817466cbSJens Wiklander 
398817466cbSJens Wiklander cleanup:
399817466cbSJens Wiklander     mbedtls_mpi_free( &r );
400817466cbSJens Wiklander     mbedtls_mpi_free( &s );
401817466cbSJens Wiklander 
402817466cbSJens Wiklander     return( ret );
403817466cbSJens Wiklander }
404817466cbSJens Wiklander 
405817466cbSJens Wiklander /*
406817466cbSJens Wiklander  * Generate key pair
407817466cbSJens Wiklander  */
408817466cbSJens Wiklander int mbedtls_ecdsa_genkey( mbedtls_ecdsa_context *ctx, mbedtls_ecp_group_id gid,
409817466cbSJens Wiklander                   int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
410817466cbSJens Wiklander {
411817466cbSJens Wiklander     return( mbedtls_ecp_group_load( &ctx->grp, gid ) ||
412817466cbSJens Wiklander             mbedtls_ecp_gen_keypair( &ctx->grp, &ctx->d, &ctx->Q, f_rng, p_rng ) );
413817466cbSJens Wiklander }
414817466cbSJens Wiklander 
415817466cbSJens Wiklander /*
416817466cbSJens Wiklander  * Set context from an mbedtls_ecp_keypair
417817466cbSJens Wiklander  */
418817466cbSJens Wiklander int mbedtls_ecdsa_from_keypair( mbedtls_ecdsa_context *ctx, const mbedtls_ecp_keypair *key )
419817466cbSJens Wiklander {
420817466cbSJens Wiklander     int ret;
421817466cbSJens Wiklander 
422817466cbSJens Wiklander     if( ( ret = mbedtls_ecp_group_copy( &ctx->grp, &key->grp ) ) != 0 ||
423817466cbSJens Wiklander         ( ret = mbedtls_mpi_copy( &ctx->d, &key->d ) ) != 0 ||
424817466cbSJens Wiklander         ( ret = mbedtls_ecp_copy( &ctx->Q, &key->Q ) ) != 0 )
425817466cbSJens Wiklander     {
426817466cbSJens Wiklander         mbedtls_ecdsa_free( ctx );
427817466cbSJens Wiklander     }
428817466cbSJens Wiklander 
429817466cbSJens Wiklander     return( ret );
430817466cbSJens Wiklander }
431817466cbSJens Wiklander 
432817466cbSJens Wiklander /*
433817466cbSJens Wiklander  * Initialize context
434817466cbSJens Wiklander  */
435817466cbSJens Wiklander void mbedtls_ecdsa_init( mbedtls_ecdsa_context *ctx )
436817466cbSJens Wiklander {
437817466cbSJens Wiklander     mbedtls_ecp_keypair_init( ctx );
438817466cbSJens Wiklander }
439817466cbSJens Wiklander 
440817466cbSJens Wiklander /*
441817466cbSJens Wiklander  * Free context
442817466cbSJens Wiklander  */
443817466cbSJens Wiklander void mbedtls_ecdsa_free( mbedtls_ecdsa_context *ctx )
444817466cbSJens Wiklander {
445817466cbSJens Wiklander     mbedtls_ecp_keypair_free( ctx );
446817466cbSJens Wiklander }
447817466cbSJens Wiklander 
448817466cbSJens Wiklander #endif /* MBEDTLS_ECDSA_C */
449