wolfssl: fixes for CVE-2018-16870 & CVE-2019-13628
[openwrt/openwrt.git] / package / libs / wolfssl / patches / 010-Make-RsaUnPad-constant-time-when-Block-Type-2-messag.patch
1 From 278d54d95de9fa80b4ac9f6dd0f900841114ca8c Mon Sep 17 00:00:00 2001
2 From: Sean Parkinson <sean@wolfssl.com>
3 Date: Mon, 27 Aug 2018 10:16:40 +1000
4 Subject: [PATCH] Make RsaUnPad constant time when Block Type 2 message
5
6 (cherry picked from commit ab03f9291b040269ae21d33b9f01529ed8311728)
7 [cherry-pick changes]
8 Signed-off-by: Eneas U de Queiroz <cotequeiroz@gmail.com>
9
10 --- a/src/internal.c
11 +++ b/src/internal.c
12 @@ -24766,26 +24766,22 @@ static int DoSessionTicket(WOLFSSL* ssl,
13 * indistinguishable from correctly formatted RSA blocks
14 */
15
16 - ret = args->lastErr;
17 args->lastErr = 0; /* reset */
18
19 /* build PreMasterSecret */
20 ssl->arrays->preMasterSecret[0] = ssl->chVersion.major;
21 ssl->arrays->preMasterSecret[1] = ssl->chVersion.minor;
22 - if (ret == 0 && args->sigSz == SECRET_LEN &&
23 - args->output != NULL) {
24 + if (args->output != NULL) {
25 XMEMCPY(&ssl->arrays->preMasterSecret[VERSION_SZ],
26 - &args->output[VERSION_SZ],
27 - SECRET_LEN - VERSION_SZ);
28 + &args->output[VERSION_SZ],
29 + SECRET_LEN - VERSION_SZ);
30 }
31 - else {
32 - /* preMasterSecret has RNG and version set */
33 - /* return proper length and ignore error */
34 - /* error will be caught as decryption error */
35 - args->sigSz = SECRET_LEN;
36 - ret = 0;
37 - }
38 -
39 + /* preMasterSecret has RNG and version set
40 + * return proper length and ignore error
41 + * error will be caught as decryption error
42 + */
43 + args->sigSz = SECRET_LEN;
44 + ret = 0;
45 break;
46 } /* rsa_kea */
47 #endif /* !NO_RSA */
48 --- a/src/tls.c
49 +++ b/src/tls.c
50 @@ -1136,12 +1136,12 @@ static int Hmac_UpdateFinal_CT(Hmac* hma
51 else if (k < maxLen)
52 b = in[k - WOLFSSL_TLS_HMAC_INNER_SZ];
53
54 - b = ctMaskSel(atEoc, b, 0x80);
55 + b = ctMaskSel(atEoc, 0x80, b);
56 b &= ~pastEoc;
57 b &= ~isOutBlock | isEocBlock;
58
59 if (j >= blockSz - 8) {
60 - b = ctMaskSel(isOutBlock, b, lenBytes[j - (blockSz - 8)]);
61 + b = ctMaskSel(isOutBlock, lenBytes[j - (blockSz - 8)], b);
62 }
63
64 hashBlock[j] = b;
65 --- a/wolfcrypt/src/integer.c
66 +++ b/wolfcrypt/src/integer.c
67 @@ -321,6 +321,17 @@ int mp_to_unsigned_bin (mp_int * a, unsi
68 return res;
69 }
70
71 +int mp_to_unsigned_bin_len(mp_int * a, unsigned char *b, int c)
72 +{
73 + int i, len;
74 +
75 + len = mp_unsigned_bin_size(a);
76 +
77 + /* pad front w/ zeros to match length */
78 + for (i = 0; i < c - len; i++)
79 + b[i] = 0x00;
80 + return mp_to_unsigned_bin(a, b + i);
81 +}
82
83 /* creates "a" then copies b into it */
84 int mp_init_copy (mp_int * a, mp_int * b)
85 --- a/wolfcrypt/src/misc.c
86 +++ b/wolfcrypt/src/misc.c
87 @@ -341,10 +341,22 @@ STATIC INLINE byte ctMaskEq(int a, int b
88 return 0 - (a == b);
89 }
90
91 -/* Constant time - select b when mask is set and a otherwise. */
92 +/* Constant time - mask set when a != b. */
93 +STATIC INLINE byte ctMaskNotEq(int a, int b)
94 +{
95 + return 0 - (a != b);
96 +}
97 +
98 +/* Constant time - select a when mask is set and b otherwise. */
99 STATIC INLINE byte ctMaskSel(byte m, byte a, byte b)
100 {
101 - return (a & ~m) | (b & m);
102 + return (b & ~m) | (a & m);
103 +}
104 +
105 +/* Constant time - select integer a when mask is set and integer b otherwise. */
106 +STATIC INLINE int ctMaskSelInt(byte m, int a, int b)
107 +{
108 + return (b & (~(int)(char)m)) | (a & ((int)(char)m));
109 }
110
111 /* Constant time - bit set when a <= b. */
112 --- a/wolfcrypt/src/rsa.c
113 +++ b/wolfcrypt/src/rsa.c
114 @@ -989,10 +989,8 @@ static int RsaUnPad_OAEP(byte *pkcsBlock
115 ret += pkcsBlock[idx++] ^ 0x01; /* separator value is 0x01 */
116 ret += pkcsBlock[0] ^ 0x00; /* Y, the first value, should be 0 */
117
118 - if (ret != 0) {
119 - WOLFSSL_MSG("RsaUnPad_OAEP: Padding Error");
120 - return BAD_PADDING_E;
121 - }
122 + /* Return 0 data length on error. */
123 + idx = ctMaskSelInt(ctMaskEq(ret, 0), idx, pkcsBlockLen);
124
125 /* adjust pointer to correct location in array and return size of M */
126 *output = (byte*)(pkcsBlock + idx);
127 @@ -1078,48 +1076,60 @@ static int RsaUnPad_PSS(byte *pkcsBlock,
128 /* UnPad plaintext, set start to *output, return length of plaintext,
129 * < 0 on error */
130 static int RsaUnPad(const byte *pkcsBlock, unsigned int pkcsBlockLen,
131 - byte **output, byte padValue)
132 + byte **output, byte padValue)
133 {
134 - word32 maxOutputLen = (pkcsBlockLen > 10) ? (pkcsBlockLen - 10) : 0;
135 - word32 invalid = 0;
136 - word32 i = 1;
137 - word32 outputLen;
138 + int ret;
139 + word32 i;
140 + byte invalid = 0;
141
142 if (output == NULL || pkcsBlockLen == 0) {
143 return BAD_FUNC_ARG;
144 }
145
146 - if (pkcsBlock[0] != 0x0) { /* skip past zero */
147 - invalid = 1;
148 - }
149 - pkcsBlock++; pkcsBlockLen--;
150 + if (padValue == RSA_BLOCK_TYPE_1) {
151 + /* First byte must be 0x00 and Second byte, block type, 0x01 */
152 + if (pkcsBlock[0] != 0 || pkcsBlock[1] != RSA_BLOCK_TYPE_1) {
153 + WOLFSSL_MSG("RsaUnPad error, invalid formatting");
154 + return RSA_PAD_E;
155 + }
156
157 - /* Require block type padValue */
158 - invalid = (pkcsBlock[0] != padValue) || invalid;
159 + /* check the padding until we find the separator */
160 + for (i = 2; i < pkcsBlockLen && pkcsBlock[i++] == 0xFF; ) { }
161
162 - /* verify the padding until we find the separator */
163 - if (padValue == RSA_BLOCK_TYPE_1) {
164 - while (i<pkcsBlockLen && pkcsBlock[i++] == 0xFF) {/* Null body */}
165 - }
166 - else {
167 - while (i<pkcsBlockLen && pkcsBlock[i++]) {/* Null body */}
168 - }
169 + /* Minimum of 11 bytes of pre-message data and must have separator. */
170 + if (i < RSA_MIN_PAD_SZ || pkcsBlock[i-1] != 0) {
171 + WOLFSSL_MSG("RsaUnPad error, bad formatting");
172 + return RSA_PAD_E;
173 + }
174
175 - if (!(i==pkcsBlockLen || pkcsBlock[i-1]==0)) {
176 - WOLFSSL_MSG("RsaUnPad error, bad formatting");
177 - return RSA_PAD_E;
178 + *output = (byte *)(pkcsBlock + i);
179 + ret = pkcsBlockLen - i;
180 }
181 + else {
182 + word32 j;
183 + byte pastSep = 0;
184
185 - outputLen = pkcsBlockLen - i;
186 - invalid = (outputLen > maxOutputLen) || invalid;
187 + /* Decrypted with private key - unpad must be constant time. */
188 + for (i = 0, j = 2; j < pkcsBlockLen; j++) {
189 + /* Update i if not passed the separator and at separator. */
190 + i |= (~pastSep) & ctMaskEq(pkcsBlock[j], 0x00) & (j + 1);
191 + pastSep |= ctMaskEq(pkcsBlock[j], 0x00);
192 + }
193 +
194 + /* Minimum of 11 bytes of pre-message data - including leading 0x00. */
195 + invalid |= ctMaskLT(i, RSA_MIN_PAD_SZ);
196 + /* Must have seen separator. */
197 + invalid |= ~pastSep;
198 + /* First byte must be 0x00. */
199 + invalid |= ctMaskNotEq(pkcsBlock[0], 0x00);
200 + /* Check against expected block type: padValue */
201 + invalid |= ctMaskNotEq(pkcsBlock[1], padValue);
202
203 - if (invalid) {
204 - WOLFSSL_MSG("RsaUnPad error, invalid formatting");
205 - return RSA_PAD_E;
206 + *output = (byte *)(pkcsBlock + i);
207 + ret = ((int)~invalid) & (pkcsBlockLen - i);
208 }
209
210 - *output = (byte *)(pkcsBlock + i);
211 - return outputLen;
212 + return ret;
213 }
214
215 /* helper function to direct unpadding
216 @@ -1249,7 +1259,7 @@ static int wc_RsaFunctionSync(const byte
217 mp_int rnd, rndi;
218 #endif
219 int ret = 0;
220 - word32 keyLen, len;
221 + word32 keyLen;
222 #endif
223
224 #ifdef WOLFSSL_HAVE_SP_RSA
225 @@ -1308,6 +1318,7 @@ static int wc_RsaFunctionSync(const byte
226 }
227 #endif
228
229 +#ifndef TEST_UNPAD_CONSTANT_TIME
230 if (mp_read_unsigned_bin(&tmp, (byte*)in, inLen) != MP_OKAY)
231 ERROR_OUT(MP_READ_E);
232
233 @@ -1418,21 +1429,18 @@ static int wc_RsaFunctionSync(const byte
234 ERROR_OUT(RSA_BUFFER_E);
235 }
236
237 - len = mp_unsigned_bin_size(&tmp);
238 -
239 - /* pad front w/ zeros to match key length */
240 - while (len < keyLen) {
241 - *out++ = 0x00;
242 - len++;
243 - }
244 -
245 *outLen = keyLen;
246 -
247 - /* convert */
248 - if (mp_to_unsigned_bin(&tmp, out) != MP_OKAY)
249 + if (mp_to_unsigned_bin_len(&tmp, out, keyLen) != MP_OKAY)
250 ERROR_OUT(MP_TO_E);
251
252 done:
253 +#else
254 + (void)type;
255 + (void)key;
256 + (void)keyLen;
257 + XMEMCPY(out, in, inLen);
258 + *outLen = inLen;
259 +#endif
260 mp_clear(&tmp);
261 #ifdef WC_RSA_BLINDING
262 if (type == RSA_PRIVATE_DECRYPT || type == RSA_PRIVATE_ENCRYPT) {
263 @@ -1633,6 +1641,7 @@ int wc_RsaFunction(const byte* in, word3
264 }
265 #endif
266
267 +#ifndef TEST_UNPAD_CONSTANT_TIME
268 #ifndef NO_RSA_BOUNDS_CHECK
269 if (type == RSA_PRIVATE_DECRYPT &&
270 key->state == RSA_STATE_DECRYPT_EXPTMOD) {
271 @@ -1667,6 +1676,7 @@ int wc_RsaFunction(const byte* in, word3
272 return ret;
273 }
274 #endif /* NO_RSA_BOUNDS_CHECK */
275 +#endif
276
277 #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_RSA)
278 if (key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_RSA &&
279 @@ -1880,7 +1890,8 @@ static int RsaPrivateDecryptEx(byte* in,
280
281 /* if not doing this inline then allocate a buffer for it */
282 if (outPtr == NULL) {
283 - key->data = (byte*)XMALLOC(inLen, key->heap, DYNAMIC_TYPE_WOLF_BIGINT);
284 + key->data = (byte*)XMALLOC(inLen, key->heap,
285 + DYNAMIC_TYPE_WOLF_BIGINT);
286 key->dataIsAlloc = 1;
287 if (key->data == NULL) {
288 ret = MEMORY_E;
289 @@ -1909,20 +1920,29 @@ static int RsaPrivateDecryptEx(byte* in,
290 ret = wc_RsaUnPad_ex(key->data, key->dataLen, &pad, pad_value, pad_type,
291 hash, mgf, label, labelSz, saltLen,
292 mp_count_bits(&key->n), key->heap);
293 - if (ret > 0 && ret <= (int)outLen && pad != NULL) {
294 + if (rsa_type == RSA_PUBLIC_DECRYPT && ret > (int)outLen)
295 + ret = RSA_BUFFER_E;
296 + else if (ret >= 0 && pad != NULL) {
297 + char c;
298 +
299 /* only copy output if not inline */
300 if (outPtr == NULL) {
301 - XMEMCPY(out, pad, ret);
302 + word32 i, j;
303 + int start = (int)((size_t)pad - (size_t)key->data);
304 +
305 + for (i = 0, j = 0; j < key->dataLen; j++) {
306 + out[i] = key->data[j];
307 + c = ctMaskGTE(j, start);
308 + c &= ctMaskLT(i, outLen);
309 + /* 0 - no add, -1 add */
310 + i += -c;
311 + }
312 }
313 - else {
314 + else
315 *outPtr = pad;
316 - }
317 - }
318 - else if (ret >= 0) {
319 - ret = RSA_BUFFER_E;
320 - }
321 - if (ret < 0) {
322 - break;
323 +
324 + ret = ctMaskSelInt(ctMaskLTE(ret, outLen), ret, RSA_BUFFER_E);
325 + ret = ctMaskSelInt(ctMaskNotEq(ret, 0), ret, RSA_BUFFER_E);
326 }
327
328 key->state = RSA_STATE_DECRYPT_RES;
329 @@ -1934,12 +1954,14 @@ static int RsaPrivateDecryptEx(byte* in,
330 defined(HAVE_CAVIUM)
331 if (key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_RSA &&
332 pad_type != WC_RSA_PSS_PAD) {
333 - /* convert result */
334 - byte* dataLen = (byte*)&key->dataLen;
335 - ret = (dataLen[0] << 8) | (dataLen[1]);
336 + if (ret > 0) {
337 + /* convert result */
338 + byte* dataLen = (byte*)&key->dataLen;
339 + ret = (dataLen[0] << 8) | (dataLen[1]);
340
341 - if (outPtr)
342 - *outPtr = in;
343 + if (outPtr)
344 + *outPtr = in;
345 + }
346 }
347 #endif
348 break;
349 --- a/wolfcrypt/src/sp_int.c
350 +++ b/wolfcrypt/src/sp_int.c
351 @@ -286,7 +286,8 @@ int sp_leading_bit(sp_int* a)
352 * The array must be large enough for encoded number - use mp_unsigned_bin_size
353 * to calculate the number of bytes required.
354 *
355 - * a SP integer.
356 + * a SP integer.
357 + * out Array to put encoding into.
358 * returns MP_OKAY always.
359 */
360 int sp_to_unsigned_bin(sp_int* a, byte* out)
361 @@ -305,6 +306,31 @@ int sp_to_unsigned_bin(sp_int* a, byte*
362 return MP_OKAY;
363 }
364
365 +/* Convert the big number to an array of bytes in big-endian format.
366 + * The array must be large enough for encoded number - use mp_unsigned_bin_size
367 + * to calculate the number of bytes required.
368 + * Front-pads the output array with zeros make number the size of the array.
369 + *
370 + * a SP integer.
371 + * out Array to put encoding into.
372 + * outSz Size of the array.
373 + * returns MP_OKAY always.
374 + */
375 +int sp_to_unsigned_bin_len(sp_int* a, byte* out, int outSz)
376 +{
377 + int i, j, b;
378 +
379 + j = outSz - 1;
380 + for (i=0; j>=0; i++) {
381 + for (b = 0; b < SP_WORD_SIZE; b += 8) {
382 + out[j--] = a->dp[i] >> b;
383 + if (j < 0)
384 + break;
385 + }
386 + }
387 +
388 + return MP_OKAY;
389 +}
390 /* Ensure the data in the big number is zeroed.
391 *
392 * a SP integer.
393 --- a/wolfcrypt/src/tfm.c
394 +++ b/wolfcrypt/src/tfm.c
395 @@ -1964,6 +1964,48 @@ void fp_to_unsigned_bin(fp_int *a, unsig
396 fp_reverse (b, x);
397 }
398
399 +int fp_to_unsigned_bin_len(fp_int *a, unsigned char *b, int c)
400 +{
401 +#if DIGIT_BIT == 64 || DIGIT_BIT == 32
402 + int i, j, x;
403 +
404 + for (x=c-1,j=0,i=0; x >= 0; x--) {
405 + b[x] = (unsigned char)(a->dp[i] >> j);
406 + j += 8;
407 + i += j == DIGIT_BIT;
408 + j &= DIGIT_BIT - 1;
409 + }
410 +
411 + return FP_OKAY;
412 +#else
413 + int x;
414 +#ifndef WOLFSSL_SMALL_STACK
415 + fp_int t[1];
416 +#else
417 + fp_int *t;
418 +#endif
419 +
420 +#ifdef WOLFSSL_SMALL_STACK
421 + t = (fp_int*)XMALLOC(sizeof(fp_int), NULL, DYNAMIC_TYPE_TMP_BUFFER);
422 + if (t == NULL)
423 + return FP_MEM;
424 +#endif
425 +
426 + fp_init_copy(t, a);
427 +
428 + for (x = 0; x < c; x++) {
429 + b[x] = (unsigned char) (t->dp[0] & 255);
430 + fp_div_2d (t, 8, t, NULL);
431 + }
432 + fp_reverse (b, x);
433 +
434 +#ifdef WOLFSSL_SMALL_STACK
435 + XFREE(t, NULL, DYNAMIC_TYPE_TMP_BUFFER);
436 +#endif
437 + return FP_OKAY;
438 +#endif
439 +}
440 +
441 int fp_unsigned_bin_size(fp_int *a)
442 {
443 int size = fp_count_bits (a);
444 @@ -2435,6 +2477,10 @@ int mp_to_unsigned_bin (mp_int * a, unsi
445 return MP_OKAY;
446 }
447
448 +int mp_to_unsigned_bin_len(mp_int * a, unsigned char *b, int c)
449 +{
450 + return fp_to_unsigned_bin_len(a, b, c);
451 +}
452 /* reads a unsigned char array, assumes the msb is stored first [big endian] */
453 int mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c)
454 {
455 --- a/wolfssl/wolfcrypt/integer.h
456 +++ b/wolfssl/wolfcrypt/integer.h
457 @@ -277,6 +277,7 @@ MP_API int mp_unsigned_bin_size(mp_int
458 MP_API int mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c);
459 MP_API int mp_to_unsigned_bin_at_pos(int x, mp_int *t, unsigned char *b);
460 MP_API int mp_to_unsigned_bin (mp_int * a, unsigned char *b);
461 +MP_API int mp_to_unsigned_bin_len(mp_int * a, unsigned char *b, int c);
462 MP_API int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y);
463 /* end functions needed by Rsa */
464
465 --- a/wolfssl/wolfcrypt/misc.h
466 +++ b/wolfssl/wolfcrypt/misc.h
467 @@ -97,7 +97,9 @@ WOLFSSL_LOCAL byte ctMaskGTE(int a, int
468 WOLFSSL_LOCAL byte ctMaskLT(int a, int b);
469 WOLFSSL_LOCAL byte ctMaskLTE(int a, int b);
470 WOLFSSL_LOCAL byte ctMaskEq(int a, int b);
471 +WOLFSSL_LOCAL byte ctMaskNotEq(int a, int b);
472 WOLFSSL_LOCAL byte ctMaskSel(byte m, byte a, byte b);
473 +WOLFSSL_LOCAL int ctMaskSelInt(byte m, int a, int b);
474 WOLFSSL_LOCAL byte ctSetLTE(int a, int b);
475
476 #endif /* NO_INLINE */
477 --- a/wolfssl/wolfcrypt/sp_int.h
478 +++ b/wolfssl/wolfcrypt/sp_int.h
479 @@ -119,7 +119,8 @@ MP_API int sp_read_radix(sp_int* a, cons
480 MP_API int sp_cmp(sp_int* a, sp_int* b);
481 MP_API int sp_count_bits(sp_int* a);
482 MP_API int sp_leading_bit(sp_int* a);
483 -MP_API int sp_to_unsigned_bin(sp_int* a, byte* in);
484 +MP_API int sp_to_unsigned_bin(sp_int* a, byte* out);
485 +MP_API int sp_to_unsigned_bin_len(sp_int* a, byte* out, int outSz);
486 MP_API void sp_forcezero(sp_int* a);
487 MP_API int sp_copy(sp_int* a, sp_int* b);
488 MP_API int sp_set(sp_int* a, sp_int_digit d);
489 @@ -156,30 +157,31 @@ typedef sp_digit mp_digit;
490
491 #define mp_free(a)
492
493 -#define mp_init sp_init
494 -#define mp_init_multi sp_init_multi
495 -#define mp_clear sp_clear
496 -#define mp_read_unsigned_bin sp_read_unsigned_bin
497 -#define mp_unsigned_bin_size sp_unsigned_bin_size
498 -#define mp_read_radix sp_read_radix
499 -#define mp_cmp sp_cmp
500 -#define mp_count_bits sp_count_bits
501 -#define mp_leading_bit sp_leading_bit
502 -#define mp_to_unsigned_bin sp_to_unsigned_bin
503 -#define mp_forcezero sp_forcezero
504 -#define mp_copy sp_copy
505 -#define mp_set sp_set
506 -#define mp_iszero sp_iszero
507 -#define mp_clamp sp_clamp
508 -#define mp_grow sp_grow
509 -#define mp_sub_d sp_sub_d
510 -#define mp_cmp_d sp_cmp_d
511 -#define mp_mod sp_mod
512 -#define mp_zero sp_zero
513 -#define mp_add_d sp_add_d
514 -#define mp_lshd sp_lshd
515 -#define mp_add sp_add
516 -#define mp_isodd sp_isodd
517 +#define mp_init sp_init
518 +#define mp_init_multi sp_init_multi
519 +#define mp_clear sp_clear
520 +#define mp_read_unsigned_bin sp_read_unsigned_bin
521 +#define mp_unsigned_bin_size sp_unsigned_bin_size
522 +#define mp_read_radix sp_read_radix
523 +#define mp_cmp sp_cmp
524 +#define mp_count_bits sp_count_bits
525 +#define mp_leading_bit sp_leading_bit
526 +#define mp_to_unsigned_bin sp_to_unsigned_bin
527 +#define mp_to_unsigned_bin_len sp_to_unsigned_bin_len
528 +#define mp_forcezero sp_forcezero
529 +#define mp_copy sp_copy
530 +#define mp_set sp_set
531 +#define mp_iszero sp_iszero
532 +#define mp_clamp sp_clamp
533 +#define mp_grow sp_grow
534 +#define mp_sub_d sp_sub_d
535 +#define mp_cmp_d sp_cmp_d
536 +#define mp_mod sp_mod
537 +#define mp_zero sp_zero
538 +#define mp_add_d sp_add_d
539 +#define mp_lshd sp_lshd
540 +#define mp_add sp_add
541 +#define mp_isodd sp_isodd
542
543 #define MP_INT_DEFINED
544
545 --- a/wolfssl/wolfcrypt/tfm.h
546 +++ b/wolfssl/wolfcrypt/tfm.h
547 @@ -563,6 +563,7 @@ int fp_leading_bit(fp_int *a);
548 int fp_unsigned_bin_size(fp_int *a);
549 void fp_read_unsigned_bin(fp_int *a, const unsigned char *b, int c);
550 void fp_to_unsigned_bin(fp_int *a, unsigned char *b);
551 +int fp_to_unsigned_bin_len(fp_int *a, unsigned char *b, int c);
552 int fp_to_unsigned_bin_at_pos(int x, fp_int *t, unsigned char *b);
553
554 /*int fp_signed_bin_size(fp_int *a);*/
555 @@ -686,6 +687,7 @@ MP_API int mp_unsigned_bin_size(mp_int
556 MP_API int mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c);
557 MP_API int mp_to_unsigned_bin_at_pos(int x, mp_int *t, unsigned char *b);
558 MP_API int mp_to_unsigned_bin (mp_int * a, unsigned char *b);
559 +MP_API int mp_to_unsigned_bin_len(mp_int * a, unsigned char *b, int c);
560
561 MP_API int mp_sub_d(fp_int *a, fp_digit b, fp_int *c);
562 MP_API int mp_copy(fp_int* a, fp_int* b);