File Coverage

SEC.xs
Criterion Covered Total %
statement 80 80 100.0
branch 8 8 100.0
condition n/a
subroutine n/a
pod n/a
total 88 88 100.0


line stmt bran cond sub pod time code
1              
2             #define XS_Id "$Id: SEC.xs 1937 2023-09-11 09:27:16Z willem $"
3              
4              
5             =head1 NAME
6              
7             Net::DNS::SEC::libcrypto - Perl interface to OpenSSL libcrypto
8              
9             =head1 DESCRIPTION
10              
11             Perl XS extension providing access to the OpenSSL libcrypto library
12             upon which the Net::DNS::SEC cryptographic components are built.
13              
14             =head1 COPYRIGHT
15              
16             Copyright (c)2018-2023 Dick Franks
17              
18             All Rights Reserved
19              
20             =head1 LICENSE
21              
22             Permission to use, copy, modify, and distribute this software and its
23             documentation for any purpose and without fee is hereby granted, provided
24             that the original copyright notices appear in all copies and that both
25             copyright notice and this permission notice appear in supporting
26             documentation, and that the name of the author not be used in advertising
27             or publicity pertaining to distribution of the software without specific
28             prior written permission.
29              
30             THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
31             IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
32             FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
33             THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
34             LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
35             FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
36             DEALINGS IN THE SOFTWARE.
37              
38             =cut
39              
40              
41             #ifdef __cplusplus
42             extern "C" {
43             #endif
44              
45             #define PERL_NO_GET_CONTEXT
46             #define PERL_REENTRANT
47             #include
48             #include
49             #include
50              
51             #include
52              
53             #ifndef OPENSSL_VERSION_NUMBER /* 0xMNN00PP0L retain backward compatibility */
54             #define OPENSSL_VERSION_NUMBER \
55             ( (OPENSSL_VERSION_MAJOR<<28) | (OPENSSL_VERSION_MINOR<<20) | (OPENSSL_VERSION_PATCH<<4) | 0x0L )
56             #endif
57              
58             #if (OPENSSL_VERSION_NUMBER < 0x7FF00000)
59             #define API_1_1_1
60             #undef OSSL_DEPRECATED
61             #define OSSL_DEPRECATED(since) extern
62             #include
63             #include
64             #include
65             #endif
66              
67             #if !(OPENSSL_VERSION_NUMBER < 0x30000000)
68             #define API_3_0_0
69             #include
70             #include
71             static OSSL_LIB_CTX *libctx = NULL;
72             #endif
73              
74             #include
75             #include
76             #include
77              
78             #ifdef __cplusplus
79             }
80             #endif
81              
82              
83             #ifdef OPENSSL_NO_DSA
84             #define NO_DSA
85             #endif
86              
87             #ifdef OPENSSL_NO_RSA
88             #define NO_RSA
89             #endif
90              
91             #ifdef OPENSSL_NO_EC
92             #define NO_ECDSA
93             #define NO_EdDSA
94             #endif
95              
96             #ifdef OPENSSL_NO_ECX
97             #define NO_EdDSA
98             #endif
99              
100             #ifdef OPENSSL_IS_BORINGSSL
101             #ifndef NID_ED25519
102             #define NO_EdDSA
103             #endif
104             #define NO_DSA
105             #define NO_SHA3
106             #endif
107              
108             #ifdef LIBRESSL_VERSION_NUMBER
109             #if (LIBRESSL_VERSION_NUMBER < 0x30702000)
110             #undef OPENSSL_VERSION_NUMBER
111             #define OPENSSL_VERSION_NUMBER 0x10100000L
112             #endif
113             #define NO_DSA
114             #define NO_SHA3
115             #endif
116              
117              
118             #if (OPENSSL_VERSION_NUMBER < 0x10001000)
119             #error ancient libcrypto version
120             #include OPENSSL_VERSION_TEXT /* in error log; by any means, however reprehensible! */
121             #endif
122              
123              
124             #if (OPENSSL_VERSION_NUMBER < 0x10100000)
125             #define EVP_MD_CTX_new() EVP_MD_CTX_create()
126             #define EVP_MD_CTX_free(ctx) EVP_MD_CTX_destroy((ctx))
127              
128 3           int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g)
129             {
130 3           d->p = p;
131 3           d->q = q;
132 3           d->g = g;
133 3           return 1;
134             }
135              
136 3           int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key)
137             {
138 3           d->priv_key = priv_key;
139 3           d->pub_key = pub_key;
140 3           return 1;
141             }
142              
143 43           int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d)
144             {
145 43           r->n = n;
146 43           r->e = e;
147 43           r->d = d;
148 43           return 1;
149             }
150              
151 43           int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q)
152             {
153 43           r->p = p;
154 43           r->q = q;
155 43           return 1;
156             }
157             #endif
158              
159              
160             #if (OPENSSL_VERSION_NUMBER < 0x10101000)
161             #define NO_EdDSA
162             #define NO_SHA3
163 14           int EVP_DigestSign(EVP_MD_CTX *ctx,
164             unsigned char *sig, size_t *sig_len,
165             const unsigned char *data, size_t data_len)
166             {
167 14           EVP_DigestUpdate( ctx, data, data_len );
168 14           return EVP_DigestSignFinal( ctx, sig, sig_len );
169             }
170              
171 38           int EVP_DigestVerify(EVP_MD_CTX *ctx,
172             const unsigned char *sig, size_t sig_len,
173             const unsigned char *data, size_t data_len)
174             {
175 38           EVP_DigestUpdate( ctx, data, data_len );
176 38           return EVP_DigestVerifyFinal( ctx, sig, sig_len );
177             }
178             #endif
179              
180              
181             #if (OPENSSL_VERSION_NUMBER < 0x30000000)
182             #define EOL
183             #endif
184              
185              
186             #define checkerr(arg) checkret( (arg), __LINE__ )
187 265           void checkret(const int ret, int line)
188             {
189 265 100         if ( ret <= 0 ) croak( "libcrypto error (%s line %d)", __FILE__, line );
190 264           }
191              
192              
193             #ifdef API_3_0_0
194             int EVP_PKEY_fromparams(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey, int selection, OSSL_PARAM_BLD *bld)
195             {
196             int retval;
197             OSSL_PARAM *params = OSSL_PARAM_BLD_to_param(bld);
198             checkerr( EVP_PKEY_fromdata_init(ctx) );
199             retval = EVP_PKEY_fromdata( ctx, ppkey, selection, params );
200             OSSL_PARAM_free(params);
201             return retval;
202             }
203             #endif
204              
205              
206             MODULE = Net::DNS::SEC PACKAGE = Net::DNS::SEC::libcrypto
207              
208             PROTOTYPES: ENABLE
209              
210             SV*
211             VERSION(void)
212             PREINIT:
213 2           char *v = SvEND( newSVpv(XS_Id, 17) );
214             CODE:
215             #ifdef EOL
216 2           RETVAL = newSVpvf( "%s %s [UNSUPPORTED]", v-5, OPENSSL_VERSION_TEXT );
217             #else
218             RETVAL = newSVpvf( "%s %s", v-5, OPENSSL_VERSION_TEXT );
219             #endif
220             OUTPUT:
221             RETVAL
222              
223              
224             #### EVP ####
225              
226             EVP_PKEY*
227             EVP_PKEY_new()
228              
229             SV*
230             EVP_sign(SV *message, EVP_PKEY *pkey, const EVP_MD *md=NULL)
231             INIT:
232             #define msgbuf (unsigned char*) SvPVX(message)
233             #define msglen SvCUR(message)
234 14           EVP_MD_CTX *ctx = EVP_MD_CTX_new();
235             unsigned char sigbuf[512]; /* RFC3110(2) */
236 14           STRLEN buflen = sizeof(sigbuf);
237             int error;
238             CODE:
239 14           checkerr( EVP_DigestSignInit( ctx, NULL, md, NULL, pkey ) );
240 14           error = EVP_DigestSign( ctx, sigbuf, &buflen, msgbuf, msglen );
241 14           EVP_MD_CTX_free(ctx);
242 14           EVP_PKEY_free(pkey);
243 14           checkerr(error);
244 14           RETVAL = newSVpvn( (char*)sigbuf, buflen );
245             OUTPUT:
246             RETVAL
247              
248             int
249             EVP_verify(SV *message, SV *signature, EVP_PKEY *pkey, const EVP_MD *md=NULL)
250             INIT:
251             #define sigbuf (unsigned char*) SvPVX(signature)
252             #define siglen SvCUR(signature)
253 38           EVP_MD_CTX *ctx = EVP_MD_CTX_new();
254             CODE:
255 38           checkerr( EVP_DigestVerifyInit( ctx, NULL, md, NULL, pkey ) );
256 38           RETVAL = EVP_DigestVerify( ctx, sigbuf, siglen, msgbuf, msglen );
257 38           EVP_MD_CTX_free(ctx);
258 38           EVP_PKEY_free(pkey);
259             OUTPUT:
260             RETVAL
261              
262              
263             EVP_MD_CTX*
264             EVP_MD_CTX_new()
265              
266             void
267             EVP_MD_CTX_free(EVP_MD_CTX *ctx)
268              
269             void
270             EVP_DigestInit(EVP_MD_CTX *ctx, const EVP_MD *type)
271             CODE:
272 18           checkerr( EVP_DigestInit( ctx, type ) );
273              
274             void
275             EVP_DigestUpdate(EVP_MD_CTX *ctx, SV *message)
276             CODE:
277 18           checkerr( EVP_DigestUpdate( ctx, msgbuf, msglen ) );
278              
279             SV*
280             EVP_DigestFinal(EVP_MD_CTX *ctx)
281             INIT:
282             unsigned char digest[EVP_MAX_MD_SIZE];
283 12           unsigned int size = sizeof(digest);
284             CODE:
285 12           checkerr( EVP_DigestFinal( ctx, digest, &size ) );
286 12           RETVAL = newSVpvn( (char*)digest, size );
287             OUTPUT:
288             RETVAL
289              
290              
291             const EVP_MD*
292             EVP_md5()
293              
294             const EVP_MD*
295             EVP_sha1()
296              
297             const EVP_MD*
298             EVP_sha224()
299              
300             const EVP_MD*
301             EVP_sha256()
302              
303             const EVP_MD*
304             EVP_sha384()
305              
306             const EVP_MD*
307             EVP_sha512()
308              
309              
310             #ifndef NO_SHA3
311             const EVP_MD*
312             EVP_sha3_224()
313              
314             const EVP_MD*
315             EVP_sha3_256()
316              
317             const EVP_MD*
318             EVP_sha3_384()
319              
320             const EVP_MD*
321             EVP_sha3_512()
322              
323             #endif
324              
325              
326             #### DSA ####
327              
328             #ifndef NO_DSA
329              
330             EVP_PKEY*
331             EVP_PKEY_new_DSA(SV *p_SV, SV *q_SV, SV *g_SV, SV *y_SV, SV *x_SV)
332             INIT:
333             #ifndef API_3_0_0
334 3           DSA *dsa = DSA_new();
335             #else
336             EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name( libctx, "DSA", NULL );
337             OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new();
338             #endif
339 3           BIGNUM *p = BN_bin2bn( (unsigned char*) SvPVX(p_SV), SvCUR(p_SV), NULL );
340 3           BIGNUM *q = BN_bin2bn( (unsigned char*) SvPVX(q_SV), SvCUR(q_SV), NULL );
341 3           BIGNUM *g = BN_bin2bn( (unsigned char*) SvPVX(g_SV), SvCUR(g_SV), NULL );
342 3           BIGNUM *x = BN_bin2bn( (unsigned char*) SvPVX(x_SV), SvCUR(x_SV), NULL );
343 3           BIGNUM *y = BN_bin2bn( (unsigned char*) SvPVX(y_SV), SvCUR(y_SV), NULL );
344             CODE:
345             #ifndef API_3_0_0
346 3           RETVAL = EVP_PKEY_new();
347 3           checkerr( DSA_set0_pqg( dsa, p, q, g ) );
348 3           checkerr( DSA_set0_key( dsa, y, x ) );
349 3           checkerr( EVP_PKEY_assign( RETVAL, EVP_PKEY_DSA, (char*)dsa ) );
350             #else
351             RETVAL = NULL;
352             checkerr( OSSL_PARAM_BLD_push_BN( bld, OSSL_PKEY_PARAM_FFC_P, p ) );
353             checkerr( OSSL_PARAM_BLD_push_BN( bld, OSSL_PKEY_PARAM_FFC_Q, q ) );
354             checkerr( OSSL_PARAM_BLD_push_BN( bld, OSSL_PKEY_PARAM_FFC_G, g ) );
355             checkerr( OSSL_PARAM_BLD_push_BN( bld, OSSL_PKEY_PARAM_PUB_KEY, y ) );
356             if ( SvCUR(x_SV) > 0 ) {
357             checkerr( OSSL_PARAM_BLD_push_BN( bld, OSSL_PKEY_PARAM_PRIV_KEY, x ) );
358             checkerr( EVP_PKEY_fromparams( ctx, &RETVAL, EVP_PKEY_KEYPAIR, bld ) );
359             } else {
360             checkerr( EVP_PKEY_fromparams( ctx, &RETVAL, EVP_PKEY_PUBLIC_KEY, bld ) );
361             }
362             OSSL_PARAM_BLD_free(bld);
363             EVP_PKEY_CTX_free(ctx);
364             BN_free(p);
365             BN_free(q);
366             BN_free(g);
367             BN_free(x);
368             BN_free(y);
369             #endif
370             OUTPUT:
371             RETVAL
372              
373             #endif
374              
375              
376             #### RSA ####
377              
378             #ifndef NO_RSA
379              
380             EVP_PKEY*
381             EVP_PKEY_new_RSA(SV *n_SV, SV *e_SV, SV *d_SV, SV *p_SV, SV *q_SV)
382             INIT:
383             #ifndef API_3_0_0
384 43           RSA *rsa = RSA_new();
385             #else
386             EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name( libctx, "RSA", NULL );
387             OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new();
388             #endif
389 43           BIGNUM *n = BN_bin2bn( (unsigned char*) SvPVX(n_SV), SvCUR(n_SV), NULL );
390 43           BIGNUM *e = BN_bin2bn( (unsigned char*) SvPVX(e_SV), SvCUR(e_SV), NULL );
391 43           BIGNUM *d = BN_bin2bn( (unsigned char*) SvPVX(d_SV), SvCUR(d_SV), NULL );
392 43           BIGNUM *p = BN_bin2bn( (unsigned char*) SvPVX(p_SV), SvCUR(p_SV), NULL );
393 43           BIGNUM *q = BN_bin2bn( (unsigned char*) SvPVX(q_SV), SvCUR(q_SV), NULL );
394             CODE:
395             #ifndef API_3_0_0
396 43           RETVAL = EVP_PKEY_new();
397 43           checkerr( RSA_set0_factors( rsa, p, q ) );
398 43           checkerr( RSA_set0_key( rsa, n, e, d ) );
399 43           checkerr( EVP_PKEY_assign( RETVAL, EVP_PKEY_RSA, (char*)rsa ) );
400             #else
401             RETVAL = NULL;
402             checkerr( OSSL_PARAM_BLD_push_BN( bld, OSSL_PKEY_PARAM_RSA_N, n ) );
403             checkerr( OSSL_PARAM_BLD_push_BN( bld, OSSL_PKEY_PARAM_RSA_E, e ) );
404             if ( SvCUR(p_SV) > 0 ) {
405             checkerr( OSSL_PARAM_BLD_push_BN( bld, OSSL_PKEY_PARAM_RSA_D, d ) );
406             checkerr( OSSL_PARAM_BLD_push_BN( bld, OSSL_PKEY_PARAM_RSA_FACTOR, p ) );
407             checkerr( OSSL_PARAM_BLD_push_BN( bld, OSSL_PKEY_PARAM_RSA_FACTOR, q ) );
408             checkerr( EVP_PKEY_fromparams( ctx, &RETVAL, EVP_PKEY_KEYPAIR, bld ) );
409             } else {
410             checkerr( EVP_PKEY_fromparams( ctx, &RETVAL, EVP_PKEY_PUBLIC_KEY, bld ) );
411             }
412             OSSL_PARAM_BLD_free(bld);
413             EVP_PKEY_CTX_free(ctx);
414             BN_free(n);
415             BN_free(e);
416             BN_free(d);
417             BN_free(p);
418             BN_free(q);
419             #endif
420             OUTPUT:
421             RETVAL
422              
423             #endif
424              
425              
426             #### ECDSA ####
427              
428             #ifndef NO_ECDSA
429              
430             EVP_PKEY*
431             EVP_PKEY_new_ECDSA(SV *curve, SV *qx_SV, SV *qy_SV)
432             INIT:
433             #ifdef API_1_1_1
434 6           EC_KEY *eckey = NULL;
435             #else
436             EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name( libctx, "EC", NULL );
437             OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new();
438             #endif
439 6           char *name = SvPVX(curve);
440 6           BIGNUM *qx = BN_bin2bn( (unsigned char*) SvPVX(qx_SV), SvCUR(qx_SV), NULL );
441 6           BIGNUM *qy = BN_bin2bn( (unsigned char*) SvPVX(qy_SV), SvCUR(qy_SV), NULL );
442             CODE:
443             #ifdef API_1_1_1
444 6           RETVAL = EVP_PKEY_new();
445 6 100         if ( strcmp(name,"P-256") == 0 ) eckey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
446 6 100         if ( strcmp(name,"P-384") == 0 ) eckey = EC_KEY_new_by_curve_name(NID_secp384r1);
447 6 100         if ( SvCUR(qy_SV) > 0 ) {
448 4           checkerr( EC_KEY_set_public_key_affine_coordinates( eckey, qx, qy ) );
449             } else {
450 2           checkerr( EC_KEY_set_private_key( eckey, qx ) );
451             }
452 6           checkerr( EVP_PKEY_assign( RETVAL, EVP_PKEY_EC, (char*)eckey ) );
453             #else
454             RETVAL = NULL;
455             checkerr( OSSL_PARAM_BLD_push_utf8_string( bld, OSSL_PKEY_PARAM_GROUP_NAME, name, 0 ) );
456             if ( SvCUR(qy_SV) > 0 ) {
457             checkerr( OSSL_PARAM_BLD_push_BN( bld, OSSL_PKEY_PARAM_EC_PUB_X, qx ) );
458             checkerr( OSSL_PARAM_BLD_push_BN( bld, OSSL_PKEY_PARAM_EC_PUB_Y, qy ) );
459             checkerr( EVP_PKEY_fromparams( ctx, &RETVAL, EVP_PKEY_PUBLIC_KEY, bld ) );
460             } else {
461             checkerr( OSSL_PARAM_BLD_push_BN( bld, OSSL_PKEY_PARAM_PRIV_KEY, qx ) );
462             checkerr( EVP_PKEY_fromparams( ctx, &RETVAL, EVP_PKEY_KEYPAIR, bld ) );
463             }
464             OSSL_PARAM_BLD_free(bld);
465             EVP_PKEY_CTX_free(ctx);
466             #endif
467 6           BN_clear_free(qx);
468 6           BN_clear_free(qy);
469             OUTPUT:
470             RETVAL
471              
472             #endif
473              
474              
475             #### EdDSA ####
476              
477             #ifndef NO_EdDSA
478              
479             EVP_PKEY*
480             EVP_PKEY_new_EdDSA(SV *curve, SV *public, SV *private=NULL)
481             INIT:
482             #ifndef API_3_0_0
483             char *name = SvPVX(curve);
484             int nid = 0;
485             #else
486             OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new();
487             EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name( libctx, SvPVX(curve), NULL );
488             #endif
489             CODE:
490             RETVAL = NULL;
491             #ifndef API_3_0_0
492             if ( strcmp(name,"ED25519") == 0 ) nid = NID_ED25519;
493             #ifdef NID_ED448 /* not yet implemented in BoringSSL & LibreSSL */
494             if ( strcmp(name,"ED448") == 0 ) nid = NID_ED448;
495             #endif
496             if ( private == NULL ) {
497             RETVAL = EVP_PKEY_new_raw_public_key( nid, NULL, (unsigned char*) SvPVX(public), SvCUR(public) );
498             } else {
499             RETVAL = EVP_PKEY_new_raw_private_key( nid, NULL, (unsigned char*) SvPVX(private), SvCUR(private) );
500             }
501             #else
502             if ( private == NULL ) {
503             checkerr( OSSL_PARAM_BLD_push_octet_string( bld, OSSL_PKEY_PARAM_PUB_KEY, SvPVX(public), SvCUR(public) ) );
504             checkerr( EVP_PKEY_fromparams( ctx, &RETVAL, EVP_PKEY_PUBLIC_KEY, bld ) );
505             } else {
506             checkerr( OSSL_PARAM_BLD_push_octet_string( bld, OSSL_PKEY_PARAM_PRIV_KEY, SvPVX(private), SvCUR(private) ) );
507             checkerr( EVP_PKEY_fromparams( ctx, &RETVAL, EVP_PKEY_KEYPAIR, bld ) );
508             }
509             OSSL_PARAM_BLD_free(bld);
510             EVP_PKEY_CTX_free(ctx);
511             #endif
512             OUTPUT:
513             RETVAL
514              
515             #endif
516              
517              
518             ####################
519              
520             void
521             checkerr(int ret)
522              
523              
524             #ifdef croak_memory_wrap
525             void
526             croak_memory_wrap()
527              
528             #endif
529              
530              
531             #ifdef DEBUG
532             void
533             ERR_print_errors(SV *filename)
534             CODE:
535             BIO *bio = BIO_new_file( SvPVX(filename), "w" );
536             ERR_print_errors(bio);
537             BIO_free(bio);
538              
539             #endif
540              
541             ####################
542