xref: /freebsd/crypto/openssl/test/recipes/20-test_pkeyutl.t (revision f1c4c3daccbaf3820f0e2224de53df12fc952fcc)
1#! /usr/bin/env perl
2# Copyright 2018-2025 The OpenSSL Project Authors. All Rights Reserved.
3#
4# Licensed under the Apache License 2.0 (the "License").  You may not use
5# this file except in compliance with the License.  You can obtain a copy
6# in the file LICENSE in the source distribution or at
7# https://www.openssl.org/source/license.html
8
9use strict;
10use warnings;
11
12use File::Spec;
13use File::Basename;
14use OpenSSL::Test qw/:DEFAULT srctop_file ok_nofips with/;
15use OpenSSL::Test::Utils;
16use File::Compare qw/compare_text compare/;
17
18setup("test_pkeyutl");
19
20plan tests => 27;
21
22# For the tests below we use the cert itself as the TBS file
23
24SKIP: {
25    skip "Skipping tests that require EC, SM2 or SM3", 4
26        if disabled("ec") || disabled("sm2") || disabled("sm3");
27
28    # SM2
29    ok_nofips(run(app(([ 'openssl', 'pkeyutl', '-sign',
30                      '-in', srctop_file('test', 'certs', 'sm2.pem'),
31                      '-inkey', srctop_file('test', 'certs', 'sm2.key'),
32                      '-out', 'sm2.sig', '-rawin',
33                      '-digest', 'sm3', '-pkeyopt', 'distid:someid']))),
34                      "Sign a piece of data using SM2");
35    ok_nofips(run(app(([ 'openssl', 'pkeyutl',
36                      '-verify', '-certin',
37                      '-in', srctop_file('test', 'certs', 'sm2.pem'),
38                      '-inkey', srctop_file('test', 'certs', 'sm2.pem'),
39                      '-sigfile', 'sm2.sig', '-rawin',
40                      '-digest', 'sm3', '-pkeyopt', 'distid:someid']))),
41                      "Verify an SM2 signature against a piece of data");
42    ok_nofips(run(app(([ 'openssl', 'pkeyutl', '-encrypt',
43                      '-in', srctop_file('test', 'data2.bin'),
44                      '-inkey', srctop_file('test', 'certs', 'sm2-pub.key'),
45                      '-pubin', '-out', 'sm2.enc']))),
46                      "Encrypt a piece of data using SM2");
47    ok_nofips(run(app(([ 'openssl', 'pkeyutl', '-decrypt',
48                      '-in', 'sm2.enc',
49                      '-inkey', srctop_file('test', 'certs', 'sm2.key'),
50                      '-out', 'sm2.dat'])))
51                      && compare_text('sm2.dat',
52                                      srctop_file('test', 'data2.bin')) == 0,
53                      "Decrypt a piece of data using SM2");
54}
55
56SKIP: {
57    skip "Skipping tests that require ECX", 7
58        if disabled("ecx");
59
60    # Ed25519
61    ok(run(app(([ 'openssl', 'pkeyutl', '-sign', '-in',
62                  srctop_file('test', 'certs', 'server-ed25519-cert.pem'),
63                  '-inkey', srctop_file('test', 'certs', 'server-ed25519-key.pem'),
64                  '-out', 'Ed25519.sig']))),
65                  "Sign a piece of data using Ed25519");
66    ok(run(app(([ 'openssl', 'pkeyutl', '-verify', '-certin', '-in',
67                  srctop_file('test', 'certs', 'server-ed25519-cert.pem'),
68                  '-inkey', srctop_file('test', 'certs', 'server-ed25519-cert.pem'),
69                  '-sigfile', 'Ed25519.sig']))),
70                  "Verify an Ed25519 signature against a piece of data");
71    #Check for failure return code
72    with({ exit_checker => sub { return shift == 1; } },
73        sub {
74            ok(run(app(([ 'openssl', 'pkeyutl', '-verifyrecover', '-in', 'Ed25519.sig',
75                          '-inkey', srctop_file('test', 'certs', 'server-ed25519-key.pem')]))),
76               "Cannot use -verifyrecover with EdDSA");
77        });
78
79    # Ed448
80    ok(run(app(([ 'openssl', 'pkeyutl', '-sign', '-in',
81                  srctop_file('test', 'certs', 'server-ed448-cert.pem'),
82                  '-inkey', srctop_file('test', 'certs', 'server-ed448-key.pem'),
83                  '-out', 'Ed448.sig', '-rawin']))),
84                  "Sign a piece of data using Ed448");
85    ok(run(app(([ 'openssl', 'pkeyutl', '-verify', '-certin', '-in',
86                  srctop_file('test', 'certs', 'server-ed448-cert.pem'),
87                  '-inkey', srctop_file('test', 'certs', 'server-ed448-cert.pem'),
88                  '-sigfile', 'Ed448.sig', '-rawin']))),
89                  "Verify an Ed448 signature against a piece of data");
90    ok(run(app(([ 'openssl', 'pkeyutl', '-sign', '-in',
91                  srctop_file('test', 'certs', 'server-ed448-cert.pem'),
92                  '-inkey', srctop_file('test', 'certs', 'server-ed448-key.pem'),
93                  '-out', 'Ed448.sig']))),
94                  "Sign a piece of data using Ed448 -rawin no more needed");
95    ok(run(app(([ 'openssl', 'pkeyutl', '-verify', '-certin', '-in',
96                  srctop_file('test', 'certs', 'server-ed448-cert.pem'),
97                  '-inkey', srctop_file('test', 'certs', 'server-ed448-cert.pem'),
98                  '-sigfile', 'Ed448.sig']))),
99                  "Verify an Ed448 signature against a piece of data, no -rawin");
100}
101
102my $sigfile;
103sub tsignverify {
104    my $testtext = shift;
105    my $privkey = shift;
106    my $pubkey = shift;
107    my @extraopts = @_;
108
109    my $data_to_sign = srctop_file('test', 'data.bin');
110    my $other_data = srctop_file('test', 'data2.bin');
111    $sigfile = basename($privkey, '.pem') . '.sig';
112
113    my @args = ();
114    plan tests => 5;
115
116    @args = ('openssl', 'pkeyutl', '-sign',
117             '-inkey', $privkey,
118             '-out', $sigfile,
119             '-in', $data_to_sign);
120    push(@args, @extraopts);
121    ok(run(app([@args])),
122       $testtext.": Generating signature");
123
124    @args = ('openssl', 'pkeyutl', '-sign',
125             '-inkey', $privkey,
126             '-keyform', 'DER',
127             '-out', $sigfile,
128             '-in', $data_to_sign);
129    push(@args, @extraopts);
130    #Check for failure return code
131    with({ exit_checker => sub { return shift == 1; } },
132        sub {
133            ok(run(app([@args])),
134               $testtext.": Checking that mismatching keyform fails");
135        });
136
137    @args = ('openssl', 'pkeyutl', '-verify',
138             '-inkey', $privkey,
139             '-sigfile', $sigfile,
140             '-in', $data_to_sign);
141    push(@args, @extraopts);
142    ok(run(app([@args])),
143       $testtext.": Verify signature with private key");
144
145    @args = ('openssl', 'pkeyutl', '-verify',
146             '-keyform', 'PEM',
147             '-inkey', $pubkey, '-pubin',
148             '-sigfile', $sigfile,
149             '-in', $data_to_sign);
150    push(@args, @extraopts);
151    ok(run(app([@args])),
152       $testtext.": Verify signature with public key");
153
154    @args = ('openssl', 'pkeyutl', '-verify',
155             '-inkey', $pubkey, '-pubin',
156             '-sigfile', $sigfile,
157             '-in', $other_data);
158    push(@args, @extraopts);
159    #Check for failure return code
160    with({ exit_checker => sub { return shift == 1; } },
161        sub {
162            ok(run(app([@args])),
163               $testtext.": Expect failure verifying mismatching data");
164        });
165}
166
167SKIP: {
168    skip "RSA is not supported by this OpenSSL build", 3
169        if disabled("rsa");
170
171    subtest "RSA CLI signature generation and verification" => sub {
172        tsignverify("RSA",
173                    srctop_file("test","testrsa.pem"),
174                    srctop_file("test","testrsapub.pem"),
175                    "-rawin", "-digest", "sha256");
176    };
177
178    ok(run(app((['openssl', 'pkeyutl', '-verifyrecover', '-in', $sigfile,
179                 '-pubin', '-inkey', srctop_file('test', 'testrsapub.pem')]))),
180       "RSA: Verify signature with -verifyrecover");
181
182    subtest "RSA CLI signature and verification with pkeyopt" => sub {
183        tsignverify("RSA",
184                    srctop_file("test","testrsa.pem"),
185                    srctop_file("test","testrsapub.pem"),
186                    "-rawin", "-digest", "sha256",
187                    "-pkeyopt", "rsa_padding_mode:pss");
188    };
189
190}
191
192SKIP: {
193    skip "DSA is not supported by this OpenSSL build", 1
194        if disabled("dsa");
195
196    subtest "DSA CLI signature generation and verification" => sub {
197        tsignverify("DSA",
198                    srctop_file("test","testdsa.pem"),
199                    srctop_file("test","testdsapub.pem"),
200                    "-rawin", "-digest", "sha256");
201    };
202}
203
204SKIP: {
205    skip "ECDSA is not supported by this OpenSSL build", 1
206        if disabled("ec");
207
208    subtest "ECDSA CLI signature generation and verification" => sub {
209        tsignverify("ECDSA",
210                    srctop_file("test","testec-p256.pem"),
211                    srctop_file("test","testecpub-p256.pem"),
212                    "-rawin", "-digest", "sha256");
213    };
214}
215
216SKIP: {
217    skip "EdDSA is not supported by this OpenSSL build", 4
218        if disabled("ecx");
219
220    subtest "Ed2559 CLI signature generation and verification" => sub {
221        tsignverify("Ed25519",
222                    srctop_file("test","tested25519.pem"),
223                    srctop_file("test","tested25519pub.pem"),
224                    "-rawin");
225    };
226
227    subtest "Ed448 CLI signature generation and verification" => sub {
228        tsignverify("Ed448",
229                    srctop_file("test","tested448.pem"),
230                    srctop_file("test","tested448pub.pem"),
231                    "-rawin");
232    };
233
234    subtest "Ed2559 CLI signature generation and verification, no -rawin" => sub {
235        tsignverify("Ed25519",
236                    srctop_file("test","tested25519.pem"),
237                    srctop_file("test","tested25519pub.pem"));
238    };
239
240    subtest "Ed448 CLI signature generation and verification, no -rawin" => sub {
241        tsignverify("Ed448",
242                    srctop_file("test","tested448.pem"),
243                    srctop_file("test","tested448pub.pem"));
244    };
245}
246
247#Encap/decap tests
248# openssl pkeyutl -encap -pubin -inkey rsa_pub.pem -secret secret.bin -out encap_out.bin
249# openssl pkeyutl -decap -inkey rsa_priv.pem -in encap_out.bin -out decap_out.bin
250# decap_out is equal to secret
251SKIP: {
252    skip "RSA is not supported by this OpenSSL build", 7
253        if disabled("rsa"); # Note "rsa" isn't (yet?) disablable.
254
255    # Self-compat
256    ok(run(app(([ 'openssl', 'pkeyutl', '-encap',
257                  '-inkey', srctop_file('test', 'testrsa2048pub.pem'),
258                  '-out', 'encap_out.bin', '-secret', 'secret.bin']))),
259                  "RSA pubkey encapsulation");
260    ok(run(app(([ 'openssl', 'pkeyutl', '-decap',
261                  '-inkey', srctop_file('test', 'testrsa2048.pem'),
262                  '-in', 'encap_out.bin', '-secret', 'decap_secret.bin']))),
263                  "RSA pubkey decapsulation");
264    is(compare("secret.bin", "decap_secret.bin"), 0, "Secret is correctly decapsulated");
265
266    # Legacy CLI with decap output written to '-out' and with '-kemop` specified
267    ok(run(app(([ 'openssl', 'pkeyutl', '-decap', '-kemop', 'RSASVE',
268                  '-inkey', srctop_file('test', 'testrsa2048.pem'),
269                  '-in', 'encap_out.bin', '-out', 'decap_out.bin']))),
270                  "RSA pubkey decapsulation");
271    is(compare("secret.bin", "decap_out.bin"), 0, "Secret is correctly decapsulated");
272
273    # Pregenerated
274    ok(run(app(([ 'openssl', 'pkeyutl', '-decap', '-kemop', 'RSASVE',
275                  '-inkey', srctop_file('test', 'testrsa2048.pem'),
276                  '-in', srctop_file('test', 'encap_out.bin'),
277                  '-secret', 'decap_out_etl.bin']))),
278                  "RSA pubkey decapsulation - pregenerated");
279
280    is(compare(srctop_file('test', 'encap_secret.bin'), "decap_out_etl.bin"), 0,
281               "Secret is correctly decapsulated - pregenerated");
282}
283