File Coverage

SEC.xs
Criterion Covered Total %
statement 85 85 100.0
branch 10 10 100.0
condition n/a
subroutine n/a
pod n/a
total 95 95 100.0


line stmt bran cond sub pod time code
1              
2             #define XS_Id "$Id: SEC.xs 2042 2025-12-24 10:23:11Z willem $"
3              
4              
5             =head1 NAME
6              
7             Net::DNS::SEC::libcrypto - Perl bindings for OpenSSL libcrypto
8              
9             =head1 DESCRIPTION
10              
11             Perl XS extension providing bindings for the OpenSSL libcrypto library
12             upon which the Net::DNS::SEC cryptographic components are built.
13              
14             =head1 COPYRIGHT
15              
16             Copyright (c)2018-2024 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             #include
47             #include
48             #include
49              
50             #include
51              
52             #ifdef OPENSSL_VERSION_NUMBER
53             #define OPENSSL_RELEASE ( OPENSSL_VERSION_NUMBER>>4 ) /* 0xMMmm0000 */
54             #else
55             #define OPENSSL_RELEASE ( OPENSSL_VERSION_MAJOR<<24 | OPENSSL_VERSION_MINOR<<16 )
56             #endif
57              
58             #if (OPENSSL_RELEASE < 0x03000000)
59             #define API_1_1_1
60             #include
61             #include
62             #include
63             #else
64             #include
65             #include
66             static OSSL_LIB_CTX *libctx = NULL;
67             #endif
68              
69             #include
70             #include
71             #include
72              
73             #ifdef __cplusplus
74             }
75             #endif
76              
77              
78             #ifdef OPENSSL_NO_DSA
79             #undef NO_DSA /* suppress compiler noise if already defined */
80             #define NO_DSA
81             #endif
82              
83             #ifdef OPENSSL_NO_RSA
84             #define NO_RSA
85             #endif
86              
87             #ifdef OPENSSL_NO_EC
88             #define NO_ECDSA
89             #define NO_EdDSA
90             #endif
91              
92             #ifdef OPENSSL_NO_ECX
93             #define NO_EdDSA
94             #endif
95              
96             #ifdef OPENSSL_NO_SM3
97             #define NO_SM3
98             #endif
99              
100              
101             #if (OPENSSL_RELEASE < 0x01010100) /* OpenSSL support status */
102             #error deprecated OpenSSL version
103             #include OPENSSL_VERSION_TEXT /* in error log; by any means, however reprehensible! */
104             #elif (OPENSSL_RELEASE < 0x03000000)
105             #define EOL 20230911
106             #elif (OPENSSL_RELEASE < 0x03010000)
107             #define EOL 20260907
108             #elif (OPENSSL_RELEASE < 0x03030000)
109             #define EOL 20251123
110             #elif (OPENSSL_RELEASE < 0x03040000)
111             #define EOL 20260409
112             #elif (OPENSSL_RELEASE < 0x03050000)
113             #define EOL 20261022
114             #elif (OPENSSL_RELEASE < 0x03060000)
115             #define EOL 20300408
116             #elif (OPENSSL_RELEASE < 0x03070000)
117             #define EOL 20261101
118             #endif
119              
120              
121             #ifdef API_1_1_1
122             #ifndef NID_ED25519
123             #define NO_EdDSA
124             #endif
125             #define NO_SM3
126             #endif
127              
128              
129             #ifdef OPENSSL_IS_BORINGSSL
130             #undef EOL
131             #endif
132              
133             #ifdef LIBRESSL_VERSION_NUMBER
134             #undef EOL
135             #endif
136              
137              
138             #define SV2BN(sv) BN_bin2bn( (unsigned char*) SvPVX(sv), SvCUR(sv), NULL )
139             #define UNDEF newSVpvn("",0)
140             #define UNUSED(sv) sv=sv;
141              
142             #define checkerr(arg) checkret( (arg), __LINE__ )
143 393           void checkret(const int ret, int line)
144             {
145 393 100         if ( ret <= 0 ) croak( "libcrypto error (%s line %d)", __FILE__, line );
146 392           }
147              
148              
149             #ifdef EVP_PKEY_PUBLIC_KEY
150 59           int EVP_PKEY_fromparams(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey, int selection, OSSL_PARAM_BLD *bld)
151             {
152             int retval;
153 59           OSSL_PARAM *params = OSSL_PARAM_BLD_to_param(bld);
154 59           checkerr( EVP_PKEY_fromdata_init(ctx) );
155 59           retval = EVP_PKEY_fromdata( ctx, ppkey, selection, params );
156 59           OSSL_PARAM_free(params);
157 59           return retval;
158             }
159             #endif
160              
161              
162             #ifdef EOL
163 6           char* selecttxt(int d1, int d2, char *txt)
164             { /* select text based on ISO date comparison */
165 6 100         return ( d1 > d2 ) ? txt : "";
166             }
167             #endif
168              
169              
170             MODULE = Net::DNS::SEC PACKAGE = Net::DNS::SEC::libcrypto
171              
172             PROTOTYPES: ENABLE
173              
174             SV*
175             VERSION(void)
176             INIT:
177 3           char *v = SvEND( newSVpv(XS_Id, 17) );
178             #ifdef EOL
179 3           time_t today = time( NULL );
180             char buf[10];
181             char *txt;
182             #endif
183             CODE:
184             #ifdef EOL
185 3           strftime( buf, sizeof buf, "%Y%m%d", gmtime(&today) );
186 3           txt = selecttxt( EOL, atoi(buf), "" ); /* get 100% coverage by calling this twice */
187 3           txt = selecttxt( atoi(buf), EOL, " [UNSUPPORTED]" );
188 3           RETVAL = newSVpvf( "%s %s%s", v-5, OPENSSL_VERSION_TEXT, txt );
189             #else
190             RETVAL = newSVpvf( "%s %s", v-5, OPENSSL_VERSION_TEXT );
191             #endif
192             OUTPUT:
193             RETVAL
194              
195              
196             #### EVP ####
197              
198             EVP_PKEY*
199             EVP_PKEY_new()
200              
201             SV*
202             EVP_sign(SV *message, EVP_PKEY *pkey, const EVP_MD *md=NULL)
203             INIT:
204             #define msgbuf (unsigned char*) SvPVX(message)
205             #define msglen SvCUR(message)
206 13           EVP_MD_CTX *ctx = EVP_MD_CTX_new();
207             unsigned char sigbuf[512]; /* RFC3110(2) */
208 13           STRLEN buflen = sizeof(sigbuf);
209             int error;
210             CODE:
211 13           checkerr( EVP_DigestSignInit( ctx, NULL, md, NULL, pkey ) );
212 13           error = EVP_DigestSign( ctx, sigbuf, &buflen, msgbuf, msglen );
213 13           EVP_MD_CTX_free(ctx);
214 13           EVP_PKEY_free(pkey);
215 13           checkerr(error);
216 13           RETVAL = newSVpvn( (char*)sigbuf, buflen );
217             OUTPUT:
218             RETVAL
219              
220             int
221             EVP_verify(SV *message, SV *signature, EVP_PKEY *pkey, const EVP_MD *md=NULL)
222             INIT:
223             #define sigbuf (unsigned char*) SvPVX(signature)
224             #define siglen SvCUR(signature)
225 36           EVP_MD_CTX *ctx = EVP_MD_CTX_new();
226             CODE:
227 36           checkerr( EVP_DigestVerifyInit( ctx, NULL, md, NULL, pkey ) );
228 36           RETVAL = EVP_DigestVerify( ctx, sigbuf, siglen, msgbuf, msglen );
229 36           EVP_MD_CTX_free(ctx);
230 36           EVP_PKEY_free(pkey);
231             OUTPUT:
232             RETVAL
233              
234              
235             EVP_MD_CTX*
236             EVP_MD_CTX_new()
237              
238             void
239             EVP_MD_CTX_free(EVP_MD_CTX *ctx)
240              
241             void
242             EVP_DigestInit(EVP_MD_CTX *ctx, const EVP_MD *type)
243             CODE:
244 21           checkerr( EVP_DigestInit( ctx, type ) );
245              
246             void
247             EVP_DigestUpdate(EVP_MD_CTX *ctx, SV *message)
248             CODE:
249 21           checkerr( EVP_DigestUpdate( ctx, msgbuf, msglen ) );
250              
251             SV*
252             EVP_DigestFinal(EVP_MD_CTX *ctx)
253             INIT:
254             unsigned char digest[EVP_MAX_MD_SIZE];
255 14           unsigned int size = sizeof(digest);
256             CODE:
257 14           checkerr( EVP_DigestFinal( ctx, digest, &size ) );
258 14           RETVAL = newSVpvn( (char*)digest, size );
259             OUTPUT:
260             RETVAL
261              
262              
263             const EVP_MD*
264             EVP_md5()
265              
266             const EVP_MD*
267             EVP_sha1()
268              
269             const EVP_MD*
270             EVP_sha224()
271              
272             const EVP_MD*
273             EVP_sha256()
274              
275             const EVP_MD*
276             EVP_sha384()
277              
278             const EVP_MD*
279             EVP_sha512()
280              
281              
282             #ifndef NO_SM3
283             const EVP_MD*
284             EVP_sm3()
285              
286             #endif
287              
288              
289             #### DSA ####
290              
291             #ifndef NO_DSA
292              
293             EVP_PKEY*
294             EVP_PKEY_new_DSA(SV *p_SV, SV *q_SV, SV *g_SV, SV *y_SV, SV *x_SV=UNDEF )
295             INIT:
296             #ifdef API_1_1_1
297             DSA *dsa = DSA_new();
298             #else
299             EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name( libctx, "DSA", NULL );
300             OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new();
301             BIGNUM *p, *q, *g, *x, *y;
302             #endif
303             CODE:
304             #ifdef API_1_1_1
305             RETVAL = EVP_PKEY_new();
306             checkerr( DSA_set0_pqg( dsa, SV2BN(p_SV), SV2BN(q_SV), SV2BN(g_SV) ) );
307             checkerr( DSA_set0_key( dsa, SV2BN(y_SV), SV2BN(x_SV) ) );
308             checkerr( EVP_PKEY_assign( RETVAL, EVP_PKEY_DSA, (char*)dsa ) );
309             #else
310             RETVAL = NULL;
311             checkerr( OSSL_PARAM_BLD_push_BN( bld, OSSL_PKEY_PARAM_FFC_P, p=SV2BN(p_SV) ) );
312             checkerr( OSSL_PARAM_BLD_push_BN( bld, OSSL_PKEY_PARAM_FFC_Q, q=SV2BN(q_SV) ) );
313             checkerr( OSSL_PARAM_BLD_push_BN( bld, OSSL_PKEY_PARAM_FFC_G, g=SV2BN(g_SV) ) );
314             checkerr( OSSL_PARAM_BLD_push_BN( bld, OSSL_PKEY_PARAM_PUB_KEY, y=SV2BN(y_SV) ) );
315             if ( SvCUR(x_SV) > 0 ) {
316             checkerr( OSSL_PARAM_BLD_push_BN( bld, OSSL_PKEY_PARAM_PRIV_KEY, x=SV2BN(x_SV) ) );
317             checkerr( EVP_PKEY_fromparams( ctx, &RETVAL, EVP_PKEY_KEYPAIR, bld ) );
318             BN_free(x);
319             } else {
320             checkerr( EVP_PKEY_fromparams( ctx, &RETVAL, EVP_PKEY_PUBLIC_KEY, bld ) );
321             }
322             OSSL_PARAM_BLD_free(bld);
323             EVP_PKEY_CTX_free(ctx);
324             BN_free(p);
325             BN_free(q);
326             BN_free(g);
327             BN_free(y);
328             #endif
329             OUTPUT:
330             RETVAL
331              
332             #endif
333              
334              
335             #### RSA ####
336              
337             #ifndef NO_RSA
338              
339             EVP_PKEY*
340             EVP_PKEY_new_RSA(SV *n_SV, SV *e_SV, SV *d_SV=UNDEF, SV *p1_SV=UNDEF, SV *p2_SV=UNDEF, SV *e1_SV=UNDEF, SV *e2_SV=UNDEF, SV *c_SV=UNDEF )
341             INIT:
342             #ifdef API_1_1_1
343             RSA *rsa = RSA_new();
344             #else
345 37           EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name( libctx, "RSA", NULL );
346 37           OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new();
347             BIGNUM *n, *e, *d, *p1, *p2, *e1, *e2, *c;
348             #endif
349             CODE:
350             #ifdef API_1_1_1
351             RETVAL = EVP_PKEY_new();
352             checkerr( RSA_set0_factors( rsa, SV2BN(p1_SV), SV2BN(p2_SV) ) );
353             checkerr( RSA_set0_key( rsa, SV2BN(n_SV), SV2BN(e_SV), SV2BN(d_SV) ) );
354             checkerr( EVP_PKEY_assign( RETVAL, EVP_PKEY_RSA, (char*)rsa ) );
355             UNUSED(e1_SV); UNUSED(e2_SV); UNUSED(c_SV); /* suppress unused variable warnings */
356             #else
357 37           RETVAL = NULL;
358 37           checkerr( OSSL_PARAM_BLD_push_BN( bld, OSSL_PKEY_PARAM_RSA_N, n=SV2BN(n_SV) ) );
359 37           checkerr( OSSL_PARAM_BLD_push_BN( bld, OSSL_PKEY_PARAM_RSA_E, e=SV2BN(e_SV) ) );
360 37 100         if ( SvCUR(d_SV) > 0 ) {
361 9           checkerr( OSSL_PARAM_BLD_push_BN( bld, OSSL_PKEY_PARAM_RSA_D, d=SV2BN(d_SV) ) );
362 9           checkerr( OSSL_PARAM_BLD_push_BN( bld, OSSL_PKEY_PARAM_RSA_FACTOR1, p1=SV2BN(p1_SV) ) );
363 9           checkerr( OSSL_PARAM_BLD_push_BN( bld, OSSL_PKEY_PARAM_RSA_FACTOR2, p2=SV2BN(p2_SV) ) );
364 9           checkerr( OSSL_PARAM_BLD_push_BN( bld, OSSL_PKEY_PARAM_RSA_EXPONENT1, e1=SV2BN(e1_SV) ) );
365 9           checkerr( OSSL_PARAM_BLD_push_BN( bld, OSSL_PKEY_PARAM_RSA_EXPONENT2, e2=SV2BN(e2_SV) ) );
366 9           checkerr( OSSL_PARAM_BLD_push_BN( bld, OSSL_PKEY_PARAM_RSA_COEFFICIENT1, c=SV2BN(c_SV) ) );
367 9           checkerr( EVP_PKEY_fromparams( ctx, &RETVAL, EVP_PKEY_KEYPAIR, bld ) );
368 9           BN_free(d);
369 9           BN_free(p1);
370 9           BN_free(p2);
371 9           BN_free(e1);
372 9           BN_free(e2);
373 9           BN_free(c);
374             } else {
375 28           checkerr( EVP_PKEY_fromparams( ctx, &RETVAL, EVP_PKEY_PUBLIC_KEY, bld ) );
376             }
377 37           OSSL_PARAM_BLD_free(bld);
378 37           EVP_PKEY_CTX_free(ctx);
379 37           BN_free(n);
380 37           BN_free(e);
381             #endif
382             OUTPUT:
383             RETVAL
384              
385             #endif
386              
387              
388             #### ECDSA ####
389              
390             #ifndef NO_ECDSA
391              
392             EVP_PKEY*
393             EVP_PKEY_new_ECDSA(SV *curve, SV *qx_SV, SV *qy_SV=UNDEF )
394             INIT:
395             #ifdef API_1_1_1
396             EC_KEY *eckey = NULL;
397             BIGNUM *qx, *qy;
398             #else
399 6           EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name( libctx, "EC", NULL );
400 6           OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new();
401 6           SV *ksv = newSVpvn("\4",1);
402             BIGNUM *qx;
403             #endif
404 6           char *name = SvPVX(curve);
405             CODE:
406             #ifdef API_1_1_1
407             RETVAL = EVP_PKEY_new();
408             if ( strcmp(name,"P-256") == 0 ) eckey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
409             if ( strcmp(name,"P-384") == 0 ) eckey = EC_KEY_new_by_curve_name(NID_secp384r1);
410             if ( SvCUR(qy_SV) > 0 ) {
411             checkerr( EC_KEY_set_public_key_affine_coordinates( eckey, qx=SV2BN(qx_SV), qy=SV2BN(qy_SV) ) );
412             BN_free(qx);
413             BN_free(qy);
414             } else {
415             checkerr( EC_KEY_set_private_key( eckey, qx=SV2BN(qx_SV) ) );
416             BN_clear_free(qx);
417             }
418             checkerr( EVP_PKEY_assign( RETVAL, EVP_PKEY_EC, (char*)eckey ) );
419             #else
420 6           RETVAL = NULL;
421 6           checkerr( OSSL_PARAM_BLD_push_utf8_string( bld, OSSL_PKEY_PARAM_GROUP_NAME, name, 0 ) );
422 6 100         if ( SvCUR(qy_SV) > 0 ) {
423 4           sv_catpvn_nomg(ksv, SvPVX(qx_SV), SvCUR(qx_SV));
424 4           sv_catpvn_nomg(ksv, SvPVX(qy_SV), SvCUR(qy_SV));
425 4           checkerr( OSSL_PARAM_BLD_push_octet_string( bld, OSSL_PKEY_PARAM_PUB_KEY, SvPVX(ksv), SvCUR(ksv) ) );
426 4           checkerr( EVP_PKEY_fromparams( ctx, &RETVAL, EVP_PKEY_PUBLIC_KEY, bld ) );
427             } else {
428 2           checkerr( OSSL_PARAM_BLD_push_BN( bld, OSSL_PKEY_PARAM_PRIV_KEY, qx=SV2BN(qx_SV) ) );
429 2           checkerr( EVP_PKEY_fromparams( ctx, &RETVAL, EVP_PKEY_KEYPAIR, bld ) );
430 2           BN_clear_free(qx);
431             }
432 6           OSSL_PARAM_BLD_free(bld);
433 6           EVP_PKEY_CTX_free(ctx);
434             #endif
435             OUTPUT:
436             RETVAL
437              
438             #endif
439              
440              
441             #### EdDSA ####
442              
443             #ifndef NO_EdDSA
444              
445             EVP_PKEY*
446             EVP_PKEY_new_EdDSA(SV *curve, SV *public, SV *private=NULL)
447             INIT:
448             #ifdef API_1_1_1
449             char *name = SvPVX(curve);
450             int nid = 0;
451             #else
452 16           OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new();
453 16           EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name( libctx, SvPVX(curve), NULL );
454             #endif
455             CODE:
456 16           RETVAL = NULL;
457             #ifdef API_1_1_1
458             if ( strcmp(name,"ED25519") == 0 ) nid = NID_ED25519;
459             #ifdef NID_ED448 /* not implemented in BoringSSL & LibreSSL */
460             if ( strcmp(name,"ED448") == 0 ) nid = NID_ED448;
461             #endif
462             if ( private == NULL ) {
463             RETVAL = EVP_PKEY_new_raw_public_key( nid, NULL, (unsigned char*) SvPVX(public), SvCUR(public) );
464             } else {
465             RETVAL = EVP_PKEY_new_raw_private_key( nid, NULL, (unsigned char*) SvPVX(private), SvCUR(private) );
466             }
467             #else
468 16 100         if ( private == NULL ) {
469 14           checkerr( OSSL_PARAM_BLD_push_octet_string( bld, OSSL_PKEY_PARAM_PUB_KEY, SvPVX(public), SvCUR(public) ) );
470 14           checkerr( EVP_PKEY_fromparams( ctx, &RETVAL, EVP_PKEY_PUBLIC_KEY, bld ) );
471             } else {
472 2           checkerr( OSSL_PARAM_BLD_push_octet_string( bld, OSSL_PKEY_PARAM_PRIV_KEY, SvPVX(private), SvCUR(private) ) );
473 2           checkerr( EVP_PKEY_fromparams( ctx, &RETVAL, EVP_PKEY_KEYPAIR, bld ) );
474             }
475 16           OSSL_PARAM_BLD_free(bld);
476 16           EVP_PKEY_CTX_free(ctx);
477             #endif
478             OUTPUT:
479             RETVAL
480              
481             #endif
482              
483              
484             ####################
485              
486             void
487             checkerr(int ret)
488              
489              
490             #ifdef croak_memory_wrap
491             void
492             croak_memory_wrap()
493              
494             #endif
495              
496              
497             #ifdef DEBUG
498             void
499             ERR_print_errors(SV *filename)
500             CODE:
501             BIO *bio = BIO_new_file( SvPVX(filename), "w" );
502             ERR_print_errors(bio);
503             BIO_free(bio);
504              
505             #endif
506              
507             ####################
508