Coverage Report

Created: 2025-12-03 08:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/port/cpl_sha256.cpp
Line
Count
Source
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
11.8M
#define ROTL(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
43
430M
#define ROTR(x, n) (((x) >> (n)) | ((x) << (32 - (n))))
44
45
46.5M
#define Ch(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
46
46.5M
#define Maj(x, y, z) (((x) & ((y) | (z))) | ((y) & (z)))
47
46.5M
#define SIGMA0(x) (ROTR((x), 2) ^ ROTR((x), 13) ^ ROTR((x), 22))
48
46.5M
#define SIGMA1(x) (ROTR((x), 6) ^ ROTR((x), 11) ^ ROTR((x), 25))
49
34.9M
#define sigma0(x) (ROTR((x), 7) ^ ROTR((x), 18) ^ ((x) >> 3))
50
34.9M
#define sigma1(x) (ROTR((x), 17) ^ ROTR((x), 19) ^ ((x) >> 10))
51
52
#define DO_ROUND()                                                             \
53
46.5M
    {                                                                          \
54
46.5M
        GUInt32 t1 = h + SIGMA1(e) + Ch(e, f, g) + *(Kp++) + *(W++);           \
55
46.5M
        GUInt32 t2 = SIGMA0(a) + Maj(a, b, c);                                 \
56
46.5M
        h = g;                                                                 \
57
46.5M
        g = f;                                                                 \
58
46.5M
        f = e;                                                                 \
59
46.5M
        e = d + t1;                                                            \
60
46.5M
        d = c;                                                                 \
61
46.5M
        c = b;                                                                 \
62
46.5M
        b = a;                                                                 \
63
46.5M
        a = t1 + t2;                                                           \
64
46.5M
    }
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
11.8M
    ((ROTR((x), 8) & 0xff00ff00U) | (ROTL((x), 8) & 0x00ff00ffU))
90
16.6k
#define BYTESWAP64(x) _byteswap64(x)
91
92
static inline GUInt64 _byteswap64(GUInt64 x)
93
16.6k
{
94
16.6k
    GUInt32 a = static_cast<GUInt32>(x >> 32);
95
16.6k
    GUInt32 b = static_cast<GUInt32>(x);
96
16.6k
    return (static_cast<GUInt64>(BYTESWAP(b)) << 32) |
97
16.6k
           static_cast<GUInt64>(BYTESWAP(a));
98
16.6k
}
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
void CPL_SHA256Init(CPL_SHA256Context *sc)
111
16.6k
{
112
16.6k
    sc->totalLength = 0;
113
16.6k
    sc->hash[0] = 0x6a09e667U;
114
16.6k
    sc->hash[1] = 0xbb67ae85U;
115
16.6k
    sc->hash[2] = 0x3c6ef372U;
116
16.6k
    sc->hash[3] = 0xa54ff53aU;
117
16.6k
    sc->hash[4] = 0x510e527fU;
118
16.6k
    sc->hash[5] = 0x9b05688cU;
119
16.6k
    sc->hash[6] = 0x1f83d9abU;
120
16.6k
    sc->hash[7] = 0x5be0cd19U;
121
16.6k
    sc->bufferLength = 0U;
122
16.6k
}
123
124
static GUInt32 burnStack(int size)
125
107k
{
126
107k
    GByte buf[128];
127
107k
    GUInt32 ret = 0;
128
129
107k
    memset(buf, static_cast<GByte>(size & 0xff), sizeof(buf));
130
13.8M
    for (size_t i = 0; i < sizeof(buf); i++)
131
13.7M
        ret += ret * buf[i];
132
107k
    size -= static_cast<int>(sizeof(buf));
133
107k
    if (size > 0)
134
71.5k
        ret += burnStack(size);
135
107k
    return ret;
136
107k
}
137
138
CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
139
static void CPL_SHA256Guts(CPL_SHA256Context *sc, const GUInt32 *cbuf)
140
727k
{
141
727k
    GUInt32 buf[64] = {};
142
143
727k
    GUInt32 *W = buf;
144
145
12.3M
    for (int i = 15; i >= 0; i--)
146
11.6M
    {
147
11.6M
        *(W++) = BYTESWAP(*cbuf);
148
11.6M
        cbuf++;
149
11.6M
    }
150
151
727k
    GUInt32 *W16 = &buf[0];
152
727k
    GUInt32 *W15 = &buf[1];
153
727k
    GUInt32 *W7 = &buf[9];
154
727k
    GUInt32 *W2 = &buf[14];
155
156
35.6M
    for (int i = 47; i >= 0; i--)
157
34.9M
    {
158
34.9M
        *(W++) = sigma1(*W2) + *(W7++) + sigma0(*W15) + *(W16++);
159
34.9M
        W2++;
160
34.9M
        W15++;
161
34.9M
    }
162
163
727k
    GUInt32 a = sc->hash[0];
164
727k
    GUInt32 b = sc->hash[1];
165
727k
    GUInt32 c = sc->hash[2];
166
727k
    GUInt32 d = sc->hash[3];
167
727k
    GUInt32 e = sc->hash[4];
168
727k
    GUInt32 f = sc->hash[5];
169
727k
    GUInt32 g = sc->hash[6];
170
727k
    GUInt32 h = sc->hash[7];
171
172
727k
    const GUInt32 *Kp = K;
173
727k
    W = buf;
174
175
727k
#ifndef CPL_SHA256_UNROLL
176
727k
#define CPL_SHA256_UNROLL 1
177
727k
#endif /* !CPL_SHA256_UNROLL */
178
179
727k
#if CPL_SHA256_UNROLL == 1
180
47.2M
    for (int i = 63; i >= 0; i--)
181
46.5M
        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
727k
    sc->hash[0] += a;
334
727k
    sc->hash[1] += b;
335
727k
    sc->hash[2] += c;
336
727k
    sc->hash[3] += d;
337
727k
    sc->hash[4] += e;
338
727k
    sc->hash[5] += f;
339
727k
    sc->hash[6] += g;
340
727k
    sc->hash[7] += h;
341
727k
}
342
343
void CPL_SHA256Update(CPL_SHA256Context *sc, const void *data, size_t len)
344
51.9k
{
345
51.9k
    int needBurn = 0;
346
347
51.9k
    if (sc->bufferLength)
348
33.8k
    {
349
33.8k
        const GUInt32 bufferBytesLeft = 64U - sc->bufferLength;
350
351
33.8k
        GUInt32 bytesToCopy = bufferBytesLeft;
352
33.8k
        if (bytesToCopy > len)
353
14.6k
            bytesToCopy = static_cast<GUInt32>(len);
354
355
33.8k
        memcpy(&sc->buffer.bytes[sc->bufferLength], data, bytesToCopy);
356
357
33.8k
        sc->totalLength += bytesToCopy * 8U;
358
359
33.8k
        sc->bufferLength += bytesToCopy;
360
33.8k
        data = static_cast<const GByte *>(data) + bytesToCopy;
361
33.8k
        len -= bytesToCopy;
362
363
33.8k
        if (sc->bufferLength == 64U)
364
19.1k
        {
365
19.1k
            CPL_SHA256Guts(sc, sc->buffer.words);
366
19.1k
            needBurn = 1;
367
19.1k
            sc->bufferLength = 0U;
368
19.1k
        }
369
33.8k
    }
370
371
760k
    while (len > 63U)
372
708k
    {
373
708k
        sc->totalLength += 512U;
374
375
708k
        CPL_SHA256Guts(sc, static_cast<const GUInt32 *>(data));
376
708k
        needBurn = 1;
377
378
708k
        data = static_cast<const GByte *>(data) + 64U;
379
708k
        len -= 64U;
380
708k
    }
381
382
51.9k
    if (len)
383
19.1k
    {
384
19.1k
        memcpy(&sc->buffer.bytes[sc->bufferLength], data, len);
385
386
19.1k
        sc->totalLength += static_cast<GUInt32>(len) * 8U;
387
388
19.1k
        sc->bufferLength += static_cast<GUInt32>(len);
389
19.1k
    }
390
391
51.9k
    if (needBurn)
392
35.7k
    {
393
        // Clean stack state of CPL_SHA256Guts()
394
395
        // We add dummy side effects to avoid burnStack() to be
396
        // optimized away (#6157).
397
35.7k
        static GUInt32 accumulator = 0;
398
35.7k
        accumulator += burnStack(
399
35.7k
            static_cast<int>(sizeof(GUInt32[74]) + sizeof(GUInt32 *[6]) +
400
35.7k
                             sizeof(int) + ((len % 2) ? sizeof(int) : 0)));
401
35.7k
        if (accumulator == 0xDEADBEEF)
402
0
            fprintf(stderr, "%s", ""); /*ok*/
403
35.7k
    }
404
51.9k
}
405
406
void CPL_SHA256Final(CPL_SHA256Context *sc, GByte hash[CPL_SHA256_HASH_SIZE])
407
16.6k
{
408
16.6k
    GUInt32 bytesToPad = 120U - sc->bufferLength;
409
16.6k
    if (bytesToPad > 64U)
410
14.3k
        bytesToPad -= 64U;
411
412
16.6k
    const GUInt64 lengthPad = BYTESWAP64(sc->totalLength);
413
414
16.6k
    CPL_SHA256Update(sc, padding, bytesToPad);
415
16.6k
    CPL_SHA256Update(sc, &lengthPad, 8U);
416
417
16.6k
    if (hash)
418
16.6k
    {
419
150k
        for (int i = 0; i < CPL_SHA256_HASH_WORDS; i++)
420
133k
        {
421
133k
            *reinterpret_cast<GUInt32 *>(hash) = BYTESWAP(sc->hash[i]);
422
133k
            hash += 4;
423
133k
        }
424
16.6k
    }
425
16.6k
}
426
427
void CPL_SHA256(const void *data, size_t len, GByte hash[CPL_SHA256_HASH_SIZE])
428
14.6k
{
429
14.6k
    CPL_SHA256Context sSHA256Ctxt;
430
14.6k
    CPL_SHA256Init(&sSHA256Ctxt);
431
14.6k
    CPL_SHA256Update(&sSHA256Ctxt, data, len);
432
14.6k
    CPL_SHA256Final(&sSHA256Ctxt, hash);
433
14.6k
    memset(&sSHA256Ctxt, 0, sizeof(sSHA256Ctxt));
434
14.6k
}
435
436
0
#define CPL_HMAC_SHA256_BLOCKSIZE 64U
437
438
// See
439
// https://en.wikipedia.org/wiki/Hash-based_message_authentication_code#Implementation
440
void CPL_HMAC_SHA256(const void *pKey, size_t nKeyLen, const void *pabyMessage,
441
                     size_t nMessageLen, GByte abyDigest[CPL_SHA256_HASH_SIZE])
442
0
{
443
0
    GByte abyPad[CPL_HMAC_SHA256_BLOCKSIZE] = {};
444
0
    if (nKeyLen > CPL_HMAC_SHA256_BLOCKSIZE)
445
0
    {
446
0
        CPL_SHA256(pKey, nKeyLen, abyPad);
447
0
    }
448
0
    else
449
0
    {
450
0
        memcpy(abyPad, pKey, nKeyLen);
451
0
    }
452
453
    // Compute ipad.
454
0
    for (size_t i = 0; i < CPL_HMAC_SHA256_BLOCKSIZE; i++)
455
0
        abyPad[i] = 0x36 ^ abyPad[i];
456
457
0
    CPL_SHA256Context sSHA256Ctxt;
458
0
    CPL_SHA256Init(&sSHA256Ctxt);
459
0
    CPL_SHA256Update(&sSHA256Ctxt, abyPad, CPL_HMAC_SHA256_BLOCKSIZE);
460
0
    CPL_SHA256Update(&sSHA256Ctxt, pabyMessage, nMessageLen);
461
0
    CPL_SHA256Final(&sSHA256Ctxt, abyDigest);
462
463
    // Compute opad.
464
0
    for (size_t i = 0; i < CPL_HMAC_SHA256_BLOCKSIZE; i++)
465
0
        abyPad[i] = (0x36 ^ 0x5C) ^ abyPad[i];
466
467
0
    CPL_SHA256Init(&sSHA256Ctxt);
468
0
    CPL_SHA256Update(&sSHA256Ctxt, abyPad, CPL_HMAC_SHA256_BLOCKSIZE);
469
0
    CPL_SHA256Update(&sSHA256Ctxt, abyDigest, CPL_SHA256_HASH_SIZE);
470
0
    CPL_SHA256Final(&sSHA256Ctxt, abyDigest);
471
472
0
    memset(&sSHA256Ctxt, 0, sizeof(sSHA256Ctxt));
473
0
    memset(abyPad, 0, CPL_HMAC_SHA256_BLOCKSIZE);
474
0
}
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
static int CPLOpenSSLNullPassphraseCallback(char * /*buf*/, int /*size*/,
547
                                            int /*rwflag*/, void * /*u*/)
548
0
{
549
0
    CPLError(CE_Failure, CPLE_NotSupported,
550
0
             "A passphrase was required for this private key, "
551
0
             "but this is not supported");
552
0
    return 0;
553
0
}
554
555
#endif
556
557
/************************************************************************/
558
/*                         CPL_RSA_SHA256_Sign()                        */
559
/************************************************************************/
560
561
GByte *CPL_RSA_SHA256_Sign(const char *pszPrivateKey, const void *pabyData,
562
                           unsigned int nDataLen, unsigned int *pnSignatureLen)
563
0
{
564
0
    *pnSignatureLen = 0;
565
566
#ifdef HAVE_CRYPTOPP
567
    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
        CPLString osRSAPrivKey(pszPrivateKey);
575
        static std::string HEADER = "-----BEGIN PRIVATE KEY-----";
576
        static std::string HEADER_RSA = "-----BEGIN RSA PRIVATE KEY-----";
577
        static std::string HEADER_ENCRYPTED =
578
            "-----BEGIN ENCRYPTED PRIVATE KEY-----";
579
        static std::string FOOTER = "-----END PRIVATE KEY-----";
580
581
        size_t pos1, pos2;
582
        pos1 = osRSAPrivKey.find(HEADER);
583
        if (pos1 == std::string::npos)
584
        {
585
            if (osRSAPrivKey.find(HEADER_RSA) != std::string::npos)
586
            {
587
                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
            else if (osRSAPrivKey.find(HEADER_ENCRYPTED) != std::string::npos)
595
            {
596
                CPLError(CE_Failure, CPLE_AppDefined,
597
                         "Encrypted PEM header found. Only PKCS#8 unencrypted "
598
                         "private keys are supported");
599
            }
600
            else
601
            {
602
                CPLError(CE_Failure, CPLE_AppDefined, "PEM header not found");
603
            }
604
            return nullptr;
605
        }
606
607
        pos2 = osRSAPrivKey.find(FOOTER, pos1 + 1);
608
        if (pos2 == std::string::npos)
609
        {
610
            CPLError(CE_Failure, CPLE_AppDefined, "PEM footer not found");
611
            return nullptr;
612
        }
613
614
        // Strip header and footer to get the base64-only portion
615
        pos1 = pos1 + HEADER.size();
616
        std::string osKeyB64 = osRSAPrivKey.substr(pos1, pos2 - pos1);
617
618
        // Base64 decode, place in a ByteQueue
619
        CryptoPP::ByteQueue queue;
620
        CryptoPP::Base64Decoder decoder;
621
622
        decoder.Attach(new CryptoPP::Redirector(queue));
623
        decoder.Put(reinterpret_cast<const cryptopp_byte *>(osKeyB64.data()),
624
                    osKeyB64.length());
625
        decoder.MessageEnd();
626
627
        CryptoPP::RSA::PrivateKey rsaPrivate;
628
        try
629
        {
630
            rsaPrivate.BERDecode(queue);
631
        }
632
        catch (const std::exception &e)
633
        {
634
            CPLError(CE_Failure, CPLE_AppDefined,
635
                     "Exception while decoding private key: %s", e.what());
636
            return nullptr;
637
        }
638
639
        // Check that we have consumed all bytes.
640
        if (!queue.IsEmpty())
641
        {
642
            CPLError(CE_Failure, CPLE_AppDefined,
643
                     "Invalid private key: extraneous trailing bytes");
644
            return nullptr;
645
        }
646
647
        CryptoPP::AutoSeededRandomPool prng;
648
        bool valid = rsaPrivate.Validate(prng, 3);
649
        if (!valid)
650
        {
651
            CPLError(CE_Failure, CPLE_AppDefined,
652
                     "Invalid private key: validation failed");
653
            return nullptr;
654
        }
655
656
        std::string signature;
657
        try
658
        {
659
            typedef CryptoPP::RSASS<CryptoPP::PKCS1v15,
660
                                    CryptoPP::SHA256>::Signer
661
                RSASSA_PKCS1v15_SHA256_Signer;
662
            RSASSA_PKCS1v15_SHA256_Signer signer(rsaPrivate);
663
664
            std::string message;
665
            message.assign(static_cast<const char *>(pabyData), nDataLen);
666
667
            CryptoPP::StringSource stringSource(
668
                message, true,
669
                new CryptoPP::SignerFilter(
670
                    prng, signer, new CryptoPP::StringSink(signature)));
671
        }
672
        catch (const std::exception &e)
673
        {
674
            CPLError(CE_Failure, CPLE_AppDefined, "Exception while signing: %s",
675
                     e.what());
676
            return nullptr;
677
        }
678
679
        *pnSignatureLen = static_cast<unsigned int>(signature.size());
680
        GByte *pabySignature =
681
            static_cast<GByte *>(CPLMalloc(signature.size()));
682
        memcpy(pabySignature, signature.c_str(), signature.size());
683
        return pabySignature;
684
    }
685
#endif
686
687
0
#if defined(HAVE_OPENSSL_CRYPTO)
688
0
    if (EQUAL(CPLGetConfigOption("CPL_RSA_SHA256_Sign", "OPENSSL"), "OPENSSL"))
689
0
    {
690
0
        const EVP_MD *digest = EVP_sha256();
691
0
        if (digest == nullptr)
692
0
        {
693
0
            CPLError(CE_Failure, CPLE_AppDefined, "EVP_sha256() failed");
694
0
            return nullptr;
695
0
        }
696
697
        // Old versions expect a void*, newer a const void*
698
0
        BIO *bio = BIO_new_mem_buf(
699
0
            const_cast<void *>(static_cast<const void *>(pszPrivateKey)),
700
0
            static_cast<int>(strlen(pszPrivateKey)));
701
0
        if (bio == nullptr)
702
0
        {
703
0
            CPLError(CE_Failure, CPLE_AppDefined, "BIO_new_mem_buf() failed");
704
0
            return nullptr;
705
0
        }
706
0
        EVP_PKEY *pkey = PEM_read_bio_PrivateKey(
707
0
            bio, nullptr, CPLOpenSSLNullPassphraseCallback, nullptr);
708
0
        BIO_free(bio);
709
0
        if (pkey == nullptr)
710
0
        {
711
0
            CPLError(CE_Failure, CPLE_AppDefined,
712
0
                     "PEM_read_bio_PrivateKey() failed");
713
0
            return nullptr;
714
0
        }
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
0
        {
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
0
        }
733
734
0
        EVP_MD_CTX_destroy(md_ctx);
735
0
        EVP_PKEY_free(pkey);
736
0
        return abyBuffer;
737
0
    }
738
0
#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
0
             "CPLRSASHA256Sign() not implemented: "
746
0
             "GDAL must be built against libcrypto++ or libcrypto (openssl)");
747
0
    return nullptr;
748
0
}