Line data Source code
1 : /* CPL_SHA256* functions derived from
2 : * http://code.google.com/p/ulib/source/browse/trunk/src/base/sha256sum.c?r=39
3 : */
4 :
5 : /* The MIT License
6 :
7 : Copyright (C) 2011 Zilong Tan (tzlloch@gmail.com)
8 : Copyright (C) 2015 Even Rouault <even.rouault at spatialys.com>
9 :
10 : Permission is hereby granted, free of charge, to any person obtaining
11 : a copy of this software and associated documentation files (the
12 : "Software"), to deal in the Software without restriction, including
13 : without limitation the rights to use, copy, modify, merge, publish,
14 : distribute, sublicense, and/or sell copies of the Software, and to
15 : permit persons to whom the Software is furnished to do so, subject to
16 : the following conditions:
17 :
18 : The above copyright notice and this permission notice shall be
19 : included in all copies or substantial portions of the Software.
20 :
21 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 : EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 : MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 : NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
25 : BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
26 : ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
27 : CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 : SOFTWARE.
29 : */
30 :
31 : /*
32 : * Original code (for SHA256 computation only) is derived from the author:
33 : * Allan Saddi
34 : */
35 :
36 : #include <string.h>
37 : #include "cpl_conv.h"
38 : #include "cpl_error.h"
39 : #include "cpl_sha256.h"
40 : #include "cpl_string.h"
41 :
42 : #define ROTL(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
43 : #define ROTR(x, n) (((x) >> (n)) | ((x) << (32 - (n))))
44 :
45 : #define Ch(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
46 : #define Maj(x, y, z) (((x) & ((y) | (z))) | ((y) & (z)))
47 : #define SIGMA0(x) (ROTR((x), 2) ^ ROTR((x), 13) ^ ROTR((x), 22))
48 : #define SIGMA1(x) (ROTR((x), 6) ^ ROTR((x), 11) ^ ROTR((x), 25))
49 : #define sigma0(x) (ROTR((x), 7) ^ ROTR((x), 18) ^ ((x) >> 3))
50 : #define sigma1(x) (ROTR((x), 17) ^ ROTR((x), 19) ^ ((x) >> 10))
51 :
52 : #define DO_ROUND() \
53 : { \
54 : GUInt32 t1 = h + SIGMA1(e) + Ch(e, f, g) + *(Kp++) + *(W++); \
55 : GUInt32 t2 = SIGMA0(a) + Maj(a, b, c); \
56 : h = g; \
57 : g = f; \
58 : f = e; \
59 : e = d + t1; \
60 : d = c; \
61 : c = b; \
62 : b = a; \
63 : a = t1 + t2; \
64 : }
65 :
66 : constexpr GUInt32 K[64] = {
67 : 0x428a2f98U, 0x71374491U, 0xb5c0fbcfU, 0xe9b5dba5U, 0x3956c25bU,
68 : 0x59f111f1U, 0x923f82a4U, 0xab1c5ed5U, 0xd807aa98U, 0x12835b01U,
69 : 0x243185beU, 0x550c7dc3U, 0x72be5d74U, 0x80deb1feU, 0x9bdc06a7U,
70 : 0xc19bf174U, 0xe49b69c1U, 0xefbe4786U, 0x0fc19dc6U, 0x240ca1ccU,
71 : 0x2de92c6fU, 0x4a7484aaU, 0x5cb0a9dcU, 0x76f988daU, 0x983e5152U,
72 : 0xa831c66dU, 0xb00327c8U, 0xbf597fc7U, 0xc6e00bf3U, 0xd5a79147U,
73 : 0x06ca6351U, 0x14292967U, 0x27b70a85U, 0x2e1b2138U, 0x4d2c6dfcU,
74 : 0x53380d13U, 0x650a7354U, 0x766a0abbU, 0x81c2c92eU, 0x92722c85U,
75 : 0xa2bfe8a1U, 0xa81a664bU, 0xc24b8b70U, 0xc76c51a3U, 0xd192e819U,
76 : 0xd6990624U, 0xf40e3585U, 0x106aa070U, 0x19a4c116U, 0x1e376c08U,
77 : 0x2748774cU, 0x34b0bcb5U, 0x391c0cb3U, 0x4ed8aa4aU, 0x5b9cca4fU,
78 : 0x682e6ff3U, 0x748f82eeU, 0x78a5636fU, 0x84c87814U, 0x8cc70208U,
79 : 0x90befffaU, 0xa4506cebU, 0xbef9a3f7U, 0xc67178f2U};
80 :
81 : #ifdef WORDS_BIGENDIAN
82 :
83 : #define BYTESWAP(x) (x)
84 : #define BYTESWAP64(x) (x)
85 :
86 : #else // WORDS_BIGENDIAN
87 :
88 : #define BYTESWAP(x) \
89 : ((ROTR((x), 8) & 0xff00ff00U) | (ROTL((x), 8) & 0x00ff00ffU))
90 : #define BYTESWAP64(x) _byteswap64(x)
91 :
92 4649 : static inline GUInt64 _byteswap64(GUInt64 x)
93 : {
94 4649 : GUInt32 a = static_cast<GUInt32>(x >> 32);
95 4649 : GUInt32 b = static_cast<GUInt32>(x);
96 4649 : return (static_cast<GUInt64>(BYTESWAP(b)) << 32) |
97 4649 : static_cast<GUInt64>(BYTESWAP(a));
98 : }
99 :
100 : #endif /* !(WORDS_BIGENDIAN) */
101 :
102 : constexpr GByte padding[64] = {
103 : 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
104 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
105 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
106 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
107 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
108 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
109 :
110 4649 : void CPL_SHA256Init(CPL_SHA256Context *sc)
111 : {
112 4649 : sc->totalLength = 0;
113 4649 : sc->hash[0] = 0x6a09e667U;
114 4649 : sc->hash[1] = 0xbb67ae85U;
115 4649 : sc->hash[2] = 0x3c6ef372U;
116 4649 : sc->hash[3] = 0xa54ff53aU;
117 4649 : sc->hash[4] = 0x510e527fU;
118 4649 : sc->hash[5] = 0x9b05688cU;
119 4649 : sc->hash[6] = 0x1f83d9abU;
120 4649 : sc->hash[7] = 0x5be0cd19U;
121 4649 : sc->bufferLength = 0U;
122 4649 : }
123 :
124 28869 : static GUInt32 burnStack(int size)
125 : {
126 : GByte buf[128];
127 28869 : GUInt32 ret = 0;
128 :
129 28869 : memset(buf, static_cast<GByte>(size & 0xff), sizeof(buf));
130 3722580 : for (size_t i = 0; i < sizeof(buf); i++)
131 3693710 : ret += ret * buf[i];
132 28869 : size -= static_cast<int>(sizeof(buf));
133 28869 : if (size > 0)
134 19246 : ret += burnStack(size);
135 28869 : return ret;
136 : }
137 :
138 : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
139 114834 : static void CPL_SHA256Guts(CPL_SHA256Context *sc, const GUInt32 *cbuf)
140 : {
141 114834 : GUInt32 buf[64] = {};
142 :
143 114834 : GUInt32 *W = buf;
144 :
145 1952170 : for (int i = 15; i >= 0; i--)
146 : {
147 1837340 : *(W++) = BYTESWAP(*cbuf);
148 1837340 : cbuf++;
149 : }
150 :
151 114834 : GUInt32 *W16 = &buf[0];
152 114834 : GUInt32 *W15 = &buf[1];
153 114834 : GUInt32 *W7 = &buf[9];
154 114834 : GUInt32 *W2 = &buf[14];
155 :
156 5626720 : for (int i = 47; i >= 0; i--)
157 : {
158 5511890 : *(W++) = sigma1(*W2) + *(W7++) + sigma0(*W15) + *(W16++);
159 5511890 : W2++;
160 5511890 : W15++;
161 : }
162 :
163 114834 : GUInt32 a = sc->hash[0];
164 114834 : GUInt32 b = sc->hash[1];
165 114834 : GUInt32 c = sc->hash[2];
166 114834 : GUInt32 d = sc->hash[3];
167 114834 : GUInt32 e = sc->hash[4];
168 114834 : GUInt32 f = sc->hash[5];
169 114834 : GUInt32 g = sc->hash[6];
170 114834 : GUInt32 h = sc->hash[7];
171 :
172 114834 : const GUInt32 *Kp = K;
173 114834 : W = buf;
174 :
175 : #ifndef CPL_SHA256_UNROLL
176 : #define CPL_SHA256_UNROLL 1
177 : #endif /* !CPL_SHA256_UNROLL */
178 :
179 : #if CPL_SHA256_UNROLL == 1
180 7464010 : for (int i = 63; i >= 0; i--)
181 7349180 : DO_ROUND();
182 : #elif CPL_SHA256_UNROLL == 2
183 : for (int i = 31; i >= 0; i--)
184 : {
185 : DO_ROUND();
186 : DO_ROUND();
187 : }
188 : #elif CPL_SHA256_UNROLL == 4
189 : for (int i = 15; i >= 0; i--)
190 : {
191 : DO_ROUND();
192 : DO_ROUND();
193 : DO_ROUND();
194 : DO_ROUND();
195 : }
196 : #elif CPL_SHA256_UNROLL == 8
197 : for (int i = 7; i >= 0; i--)
198 : {
199 : DO_ROUND();
200 : DO_ROUND();
201 : DO_ROUND();
202 : DO_ROUND();
203 : DO_ROUND();
204 : DO_ROUND();
205 : DO_ROUND();
206 : DO_ROUND();
207 : }
208 : #elif CPL_SHA256_UNROLL == 16
209 : for (int i = 3; i >= 0; i--)
210 : {
211 : DO_ROUND();
212 : DO_ROUND();
213 : DO_ROUND();
214 : DO_ROUND();
215 : DO_ROUND();
216 : DO_ROUND();
217 : DO_ROUND();
218 : DO_ROUND();
219 : DO_ROUND();
220 : DO_ROUND();
221 : DO_ROUND();
222 : DO_ROUND();
223 : DO_ROUND();
224 : DO_ROUND();
225 : DO_ROUND();
226 : DO_ROUND();
227 : }
228 : #elif CPL_SHA256_UNROLL == 32
229 : for (int i = 1; i >= 0; i--)
230 : {
231 : DO_ROUND();
232 : DO_ROUND();
233 : DO_ROUND();
234 : DO_ROUND();
235 : DO_ROUND();
236 : DO_ROUND();
237 : DO_ROUND();
238 : DO_ROUND();
239 : DO_ROUND();
240 : DO_ROUND();
241 : DO_ROUND();
242 : DO_ROUND();
243 : DO_ROUND();
244 : DO_ROUND();
245 : DO_ROUND();
246 : DO_ROUND();
247 : DO_ROUND();
248 : DO_ROUND();
249 : DO_ROUND();
250 : DO_ROUND();
251 : DO_ROUND();
252 : DO_ROUND();
253 : DO_ROUND();
254 : DO_ROUND();
255 : DO_ROUND();
256 : DO_ROUND();
257 : DO_ROUND();
258 : DO_ROUND();
259 : DO_ROUND();
260 : DO_ROUND();
261 : DO_ROUND();
262 : DO_ROUND();
263 : }
264 : #elif CPL_SHA256_UNROLL == 64
265 : DO_ROUND();
266 : DO_ROUND();
267 : DO_ROUND();
268 : DO_ROUND();
269 : DO_ROUND();
270 : DO_ROUND();
271 : DO_ROUND();
272 : DO_ROUND();
273 : DO_ROUND();
274 : DO_ROUND();
275 : DO_ROUND();
276 : DO_ROUND();
277 : DO_ROUND();
278 : DO_ROUND();
279 : DO_ROUND();
280 : DO_ROUND();
281 : DO_ROUND();
282 : DO_ROUND();
283 : DO_ROUND();
284 : DO_ROUND();
285 : DO_ROUND();
286 : DO_ROUND();
287 : DO_ROUND();
288 : DO_ROUND();
289 : DO_ROUND();
290 : DO_ROUND();
291 : DO_ROUND();
292 : DO_ROUND();
293 : DO_ROUND();
294 : DO_ROUND();
295 : DO_ROUND();
296 : DO_ROUND();
297 : DO_ROUND();
298 : DO_ROUND();
299 : DO_ROUND();
300 : DO_ROUND();
301 : DO_ROUND();
302 : DO_ROUND();
303 : DO_ROUND();
304 : DO_ROUND();
305 : DO_ROUND();
306 : DO_ROUND();
307 : DO_ROUND();
308 : DO_ROUND();
309 : DO_ROUND();
310 : DO_ROUND();
311 : DO_ROUND();
312 : DO_ROUND();
313 : DO_ROUND();
314 : DO_ROUND();
315 : DO_ROUND();
316 : DO_ROUND();
317 : DO_ROUND();
318 : DO_ROUND();
319 : DO_ROUND();
320 : DO_ROUND();
321 : DO_ROUND();
322 : DO_ROUND();
323 : DO_ROUND();
324 : DO_ROUND();
325 : DO_ROUND();
326 : DO_ROUND();
327 : DO_ROUND();
328 : DO_ROUND();
329 : #else
330 : #error "CPL_SHA256_UNROLL must be 1, 2, 4, 8, 16, 32, or 64!"
331 : #endif
332 :
333 114834 : sc->hash[0] += a;
334 114834 : sc->hash[1] += b;
335 114834 : sc->hash[2] += c;
336 114834 : sc->hash[3] += d;
337 114834 : sc->hash[4] += e;
338 114834 : sc->hash[5] += f;
339 114834 : sc->hash[6] += g;
340 114834 : sc->hash[7] += h;
341 114834 : }
342 :
343 17909 : void CPL_SHA256Update(CPL_SHA256Context *sc, const void *data, size_t len)
344 : {
345 17909 : int needBurn = 0;
346 :
347 17909 : if (sc->bufferLength)
348 : {
349 9108 : const GUInt32 bufferBytesLeft = 64U - sc->bufferLength;
350 :
351 9108 : GUInt32 bytesToCopy = bufferBytesLeft;
352 9108 : if (bytesToCopy > len)
353 4358 : bytesToCopy = static_cast<GUInt32>(len);
354 :
355 9108 : memcpy(&sc->buffer.bytes[sc->bufferLength], data, bytesToCopy);
356 :
357 9108 : sc->totalLength += bytesToCopy * 8U;
358 :
359 9108 : sc->bufferLength += bytesToCopy;
360 9108 : data = static_cast<const GByte *>(data) + bytesToCopy;
361 9108 : len -= bytesToCopy;
362 :
363 9108 : if (sc->bufferLength == 64U)
364 : {
365 4750 : CPL_SHA256Guts(sc, sc->buffer.words);
366 4750 : needBurn = 1;
367 4750 : sc->bufferLength = 0U;
368 : }
369 : }
370 :
371 127993 : while (len > 63U)
372 : {
373 110084 : sc->totalLength += 512U;
374 :
375 110084 : CPL_SHA256Guts(sc, static_cast<const GUInt32 *>(data));
376 110084 : needBurn = 1;
377 :
378 110084 : data = static_cast<const GByte *>(data) + 64U;
379 110084 : len -= 64U;
380 : }
381 :
382 17909 : if (len)
383 : {
384 4750 : memcpy(&sc->buffer.bytes[sc->bufferLength], data, len);
385 :
386 4750 : sc->totalLength += static_cast<GUInt32>(len) * 8U;
387 :
388 4750 : sc->bufferLength += static_cast<GUInt32>(len);
389 : }
390 :
391 17909 : if (needBurn)
392 : {
393 : // Clean stack state of CPL_SHA256Guts()
394 :
395 : // We add dummy side effects to avoid burnStack() to be
396 : // optimized away (#6157).
397 : static GUInt32 accumulator = 0;
398 19245 : accumulator += burnStack(
399 : static_cast<int>(sizeof(GUInt32[74]) + sizeof(GUInt32 *[6]) +
400 9622 : sizeof(int) + ((len % 2) ? sizeof(int) : 0)));
401 9623 : if (accumulator == 0xDEADBEEF)
402 0 : fprintf(stderr, "%s", ""); /*ok*/
403 : }
404 17910 : }
405 :
406 4649 : void CPL_SHA256Final(CPL_SHA256Context *sc, GByte hash[CPL_SHA256_HASH_SIZE])
407 : {
408 4649 : GUInt32 bytesToPad = 120U - sc->bufferLength;
409 4649 : if (bytesToPad > 64U)
410 4561 : bytesToPad -= 64U;
411 :
412 4649 : const GUInt64 lengthPad = BYTESWAP64(sc->totalLength);
413 :
414 4649 : CPL_SHA256Update(sc, padding, bytesToPad);
415 4649 : CPL_SHA256Update(sc, &lengthPad, 8U);
416 :
417 4649 : if (hash)
418 : {
419 41841 : for (int i = 0; i < CPL_SHA256_HASH_WORDS; i++)
420 : {
421 37192 : *reinterpret_cast<GUInt32 *>(hash) = BYTESWAP(sc->hash[i]);
422 37192 : hash += 4;
423 : }
424 : }
425 4649 : }
426 :
427 687 : void CPL_SHA256(const void *data, size_t len, GByte hash[CPL_SHA256_HASH_SIZE])
428 : {
429 : CPL_SHA256Context sSHA256Ctxt;
430 687 : CPL_SHA256Init(&sSHA256Ctxt);
431 687 : CPL_SHA256Update(&sSHA256Ctxt, data, len);
432 686 : CPL_SHA256Final(&sSHA256Ctxt, hash);
433 687 : memset(&sSHA256Ctxt, 0, sizeof(sSHA256Ctxt));
434 687 : }
435 :
436 : #define CPL_HMAC_SHA256_BLOCKSIZE 64U
437 :
438 : // See
439 : // https://en.wikipedia.org/wiki/Hash-based_message_authentication_code#Implementation
440 1905 : void CPL_HMAC_SHA256(const void *pKey, size_t nKeyLen, const void *pabyMessage,
441 : size_t nMessageLen, GByte abyDigest[CPL_SHA256_HASH_SIZE])
442 : {
443 1905 : GByte abyPad[CPL_HMAC_SHA256_BLOCKSIZE] = {};
444 1905 : if (nKeyLen > CPL_HMAC_SHA256_BLOCKSIZE)
445 : {
446 1 : CPL_SHA256(pKey, nKeyLen, abyPad);
447 : }
448 : else
449 : {
450 1904 : memcpy(abyPad, pKey, nKeyLen);
451 : }
452 :
453 : // Compute ipad.
454 123825 : for (size_t i = 0; i < CPL_HMAC_SHA256_BLOCKSIZE; i++)
455 121920 : abyPad[i] = 0x36 ^ abyPad[i];
456 :
457 : CPL_SHA256Context sSHA256Ctxt;
458 1905 : CPL_SHA256Init(&sSHA256Ctxt);
459 1905 : CPL_SHA256Update(&sSHA256Ctxt, abyPad, CPL_HMAC_SHA256_BLOCKSIZE);
460 1905 : CPL_SHA256Update(&sSHA256Ctxt, pabyMessage, nMessageLen);
461 1905 : CPL_SHA256Final(&sSHA256Ctxt, abyDigest);
462 :
463 : // Compute opad.
464 123825 : for (size_t i = 0; i < CPL_HMAC_SHA256_BLOCKSIZE; i++)
465 121920 : abyPad[i] = (0x36 ^ 0x5C) ^ abyPad[i];
466 :
467 1905 : CPL_SHA256Init(&sSHA256Ctxt);
468 1905 : CPL_SHA256Update(&sSHA256Ctxt, abyPad, CPL_HMAC_SHA256_BLOCKSIZE);
469 1905 : CPL_SHA256Update(&sSHA256Ctxt, abyDigest, CPL_SHA256_HASH_SIZE);
470 1905 : CPL_SHA256Final(&sSHA256Ctxt, abyDigest);
471 :
472 1905 : memset(&sSHA256Ctxt, 0, sizeof(sSHA256Ctxt));
473 1905 : memset(abyPad, 0, CPL_HMAC_SHA256_BLOCKSIZE);
474 1905 : }
475 :
476 : #ifdef HAVE_CRYPTOPP
477 :
478 : /* Begin of crypto++ headers */
479 : #ifdef _MSC_VER
480 : #pragma warning(push)
481 : #pragma warning(disable : 4189)
482 : #pragma warning(disable : 4512)
483 : #pragma warning(disable : 4244)
484 : #endif
485 :
486 : #ifdef __GNUC__
487 : #pragma GCC diagnostic push
488 : #pragma GCC diagnostic ignored "-Weffc++"
489 : #pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
490 : #pragma GCC diagnostic ignored "-Wold-style-cast"
491 : #pragma GCC diagnostic ignored "-Wshadow"
492 : #endif
493 :
494 : #ifdef USE_ONLY_CRYPTODLL_ALG
495 : #include "cryptopp/dll.h"
496 : #else
497 : #include "cryptopp/rsa.h"
498 : #include "cryptopp/queue.h"
499 : #endif
500 :
501 : #include "cryptopp/base64.h"
502 : #include "cryptopp/osrng.h"
503 :
504 : // Fix compatibility with Crypto++
505 : #if CRYPTOPP_VERSION >= 600
506 : typedef CryptoPP::byte cryptopp_byte;
507 : #else
508 : typedef byte cryptopp_byte;
509 : #endif
510 :
511 : #ifdef __GNUC__
512 : #pragma GCC diagnostic pop
513 : #endif
514 :
515 : #ifdef _MSC_VER
516 : #pragma warning(pop)
517 : #endif
518 :
519 : #endif // HAVE_CRYPTOPP
520 :
521 : #ifdef HAVE_OPENSSL_CRYPTO
522 :
523 : #if defined(__GNUC__)
524 : #pragma GCC diagnostic push
525 : #pragma GCC diagnostic ignored "-Wold-style-cast"
526 : #ifdef HAVE_WFLAG_CAST_FUNCTION_TYPE
527 : #pragma GCC diagnostic ignored "-Wcast-function-type"
528 : #endif
529 : #endif
530 :
531 : #include <openssl/bio.h>
532 : #include <openssl/evp.h>
533 : #include <openssl/pem.h>
534 :
535 : #if defined(__GNUC__)
536 : #pragma GCC diagnostic pop
537 : #endif
538 :
539 : #endif
540 :
541 : /************************************************************************/
542 : /* CPLOpenSSLNullPassphraseCallback() */
543 : /************************************************************************/
544 :
545 : #if defined(HAVE_OPENSSL_CRYPTO)
546 0 : static int CPLOpenSSLNullPassphraseCallback(char * /*buf*/, int /*size*/,
547 : int /*rwflag*/, void * /*u*/)
548 : {
549 0 : CPLError(CE_Failure, CPLE_NotSupported,
550 : "A passphrase was required for this private key, "
551 : "but this is not supported");
552 0 : return 0;
553 : }
554 :
555 : #endif
556 :
557 : /************************************************************************/
558 : /* CPL_RSA_SHA256_Sign() */
559 : /************************************************************************/
560 :
561 7 : GByte *CPL_RSA_SHA256_Sign(const char *pszPrivateKey, const void *pabyData,
562 : unsigned int nDataLen, unsigned int *pnSignatureLen)
563 : {
564 7 : *pnSignatureLen = 0;
565 :
566 : #ifdef HAVE_CRYPTOPP
567 7 : if (EQUAL(CPLGetConfigOption("CPL_RSA_SHA256_Sign", "CRYPTOPP"),
568 : "CRYPTOPP"))
569 : {
570 : // See https://www.cryptopp.com/wiki/RSA_Cryptography
571 : // https://www.cryptopp.com/wiki/RSA_Signature_Schemes#RSA_Signature_Scheme_.28PKCS_v1.5.29
572 : // https://www.cryptopp.com/wiki/Keys_and_Formats#PEM_Encoded_Keys
573 :
574 14 : CPLString osRSAPrivKey(pszPrivateKey);
575 7 : static std::string HEADER = "-----BEGIN PRIVATE KEY-----";
576 7 : static std::string HEADER_RSA = "-----BEGIN RSA PRIVATE KEY-----";
577 : static std::string HEADER_ENCRYPTED =
578 7 : "-----BEGIN ENCRYPTED PRIVATE KEY-----";
579 7 : static std::string FOOTER = "-----END PRIVATE KEY-----";
580 :
581 : size_t pos1, pos2;
582 7 : pos1 = osRSAPrivKey.find(HEADER);
583 7 : if (pos1 == std::string::npos)
584 : {
585 0 : if (osRSAPrivKey.find(HEADER_RSA) != std::string::npos)
586 : {
587 0 : CPLError(CE_Failure, CPLE_AppDefined,
588 : "'Traditional' PEM header found, whereas PKCS#8 is "
589 : "expected. You can use for example "
590 : "'openssl pkcs8 -topk8 -inform pem -in file.key "
591 : "-outform pem -nocrypt -out file.pem' to generate "
592 : "a compatible PEM file");
593 : }
594 0 : else if (osRSAPrivKey.find(HEADER_ENCRYPTED) != std::string::npos)
595 : {
596 0 : CPLError(CE_Failure, CPLE_AppDefined,
597 : "Encrypted PEM header found. Only PKCS#8 unencrypted "
598 : "private keys are supported");
599 : }
600 : else
601 : {
602 0 : CPLError(CE_Failure, CPLE_AppDefined, "PEM header not found");
603 : }
604 0 : return nullptr;
605 : }
606 :
607 7 : pos2 = osRSAPrivKey.find(FOOTER, pos1 + 1);
608 7 : if (pos2 == std::string::npos)
609 : {
610 0 : CPLError(CE_Failure, CPLE_AppDefined, "PEM footer not found");
611 0 : return nullptr;
612 : }
613 :
614 : // Strip header and footer to get the base64-only portion
615 7 : pos1 = pos1 + HEADER.size();
616 14 : std::string osKeyB64 = osRSAPrivKey.substr(pos1, pos2 - pos1);
617 :
618 : // Base64 decode, place in a ByteQueue
619 14 : CryptoPP::ByteQueue queue;
620 14 : CryptoPP::Base64Decoder decoder;
621 :
622 7 : decoder.Attach(new CryptoPP::Redirector(queue));
623 7 : decoder.Put(reinterpret_cast<const cryptopp_byte *>(osKeyB64.data()),
624 : osKeyB64.length());
625 7 : decoder.MessageEnd();
626 :
627 14 : CryptoPP::RSA::PrivateKey rsaPrivate;
628 : try
629 : {
630 7 : rsaPrivate.BERDecode(queue);
631 : }
632 0 : catch (const std::exception &e)
633 : {
634 0 : CPLError(CE_Failure, CPLE_AppDefined,
635 0 : "Exception while decoding private key: %s", e.what());
636 0 : return nullptr;
637 : }
638 :
639 : // Check that we have consumed all bytes.
640 7 : if (!queue.IsEmpty())
641 : {
642 0 : CPLError(CE_Failure, CPLE_AppDefined,
643 : "Invalid private key: extraneous trailing bytes");
644 0 : return nullptr;
645 : }
646 :
647 14 : CryptoPP::AutoSeededRandomPool prng;
648 7 : bool valid = rsaPrivate.Validate(prng, 3);
649 7 : if (!valid)
650 : {
651 0 : CPLError(CE_Failure, CPLE_AppDefined,
652 : "Invalid private key: validation failed");
653 0 : return nullptr;
654 : }
655 :
656 14 : std::string signature;
657 : try
658 : {
659 : typedef CryptoPP::RSASS<CryptoPP::PKCS1v15,
660 : CryptoPP::SHA256>::Signer
661 : RSASSA_PKCS1v15_SHA256_Signer;
662 14 : RSASSA_PKCS1v15_SHA256_Signer signer(rsaPrivate);
663 :
664 14 : std::string message;
665 7 : message.assign(static_cast<const char *>(pabyData), nDataLen);
666 :
667 : CryptoPP::StringSource stringSource(
668 : message, true,
669 : new CryptoPP::SignerFilter(
670 7 : prng, signer, new CryptoPP::StringSink(signature)));
671 : }
672 0 : catch (const std::exception &e)
673 : {
674 0 : CPLError(CE_Failure, CPLE_AppDefined, "Exception while signing: %s",
675 0 : e.what());
676 0 : return nullptr;
677 : }
678 :
679 7 : *pnSignatureLen = static_cast<unsigned int>(signature.size());
680 : GByte *pabySignature =
681 7 : static_cast<GByte *>(CPLMalloc(signature.size()));
682 7 : memcpy(pabySignature, signature.c_str(), signature.size());
683 7 : return pabySignature;
684 : }
685 : #endif
686 :
687 : #if defined(HAVE_OPENSSL_CRYPTO)
688 0 : if (EQUAL(CPLGetConfigOption("CPL_RSA_SHA256_Sign", "OPENSSL"), "OPENSSL"))
689 : {
690 0 : const EVP_MD *digest = EVP_sha256();
691 0 : if (digest == nullptr)
692 : {
693 0 : CPLError(CE_Failure, CPLE_AppDefined, "EVP_sha256() failed");
694 0 : return nullptr;
695 : }
696 :
697 : // Old versions expect a void*, newer a const void*
698 0 : BIO *bio = BIO_new_mem_buf(
699 : const_cast<void *>(static_cast<const void *>(pszPrivateKey)),
700 0 : static_cast<int>(strlen(pszPrivateKey)));
701 0 : if (bio == nullptr)
702 : {
703 0 : CPLError(CE_Failure, CPLE_AppDefined, "BIO_new_mem_buf() failed");
704 0 : return nullptr;
705 : }
706 0 : EVP_PKEY *pkey = PEM_read_bio_PrivateKey(
707 : bio, nullptr, CPLOpenSSLNullPassphraseCallback, nullptr);
708 0 : BIO_free(bio);
709 0 : if (pkey == nullptr)
710 : {
711 0 : CPLError(CE_Failure, CPLE_AppDefined,
712 : "PEM_read_bio_PrivateKey() failed");
713 0 : return nullptr;
714 : }
715 0 : EVP_MD_CTX *md_ctx = EVP_MD_CTX_create();
716 0 : CPLAssert(md_ctx != nullptr);
717 0 : int ret = EVP_SignInit(md_ctx, digest);
718 0 : CPLAssert(ret == 1);
719 0 : ret = EVP_SignUpdate(md_ctx, pabyData, nDataLen);
720 0 : CPLAssert(ret == 1);
721 0 : const int nPKeyLength = EVP_PKEY_size(pkey);
722 0 : CPLAssert(nPKeyLength > 0);
723 0 : GByte *abyBuffer = static_cast<GByte *>(CPLMalloc(nPKeyLength));
724 0 : ret = EVP_SignFinal(md_ctx, abyBuffer, pnSignatureLen, pkey);
725 0 : if (ret != 1)
726 : {
727 0 : CPLError(CE_Failure, CPLE_AppDefined, "EVP_SignFinal() failed");
728 0 : EVP_MD_CTX_destroy(md_ctx);
729 0 : EVP_PKEY_free(pkey);
730 0 : CPLFree(abyBuffer);
731 0 : return nullptr;
732 : }
733 :
734 0 : EVP_MD_CTX_destroy(md_ctx);
735 0 : EVP_PKEY_free(pkey);
736 0 : return abyBuffer;
737 : }
738 : #endif
739 :
740 0 : CPL_IGNORE_RET_VAL(pszPrivateKey);
741 0 : CPL_IGNORE_RET_VAL(pabyData);
742 0 : CPL_IGNORE_RET_VAL(nDataLen);
743 :
744 0 : CPLError(CE_Failure, CPLE_NotSupported,
745 : "CPLRSASHA256Sign() not implemented: "
746 : "GDAL must be built against libcrypto++ or libcrypto (openssl)");
747 0 : return nullptr;
748 : }
|