Skip to content
File

Blob: src/workerd/api/node/tests/crypto_sign-test.js

javascript217 lines
1// Copyright (c) 2025 Cloudflare, Inc.
2// Licensed under the Apache 2.0 license found in the LICENSE file or at:
3// https://opensource.org/licenses/Apache-2.0
4import {
5 createSign,
6 createVerify,
7 createPrivateKey,
8 createPublicKey,
9 generateKeyPairSync,
10 sign,
11 verify,
12} from 'node:crypto';
13 
14import { ok, strictEqual, throws } from 'node:assert';
15 
16const rsaSig =
17 '26bb4d9641ecec048b791322c6427f62f3f4e21f7198e9e7544c8a56af40' +
18 '27bcfe1b306291188f97ced0e3ceaa5ded1ae1406ec30e46a18434e55dc6' +
19 'c9f237e26b124bf7ec77e54483d7782b805aa9a74bbe0f4aa8658d7620e4' +
20 'd3a305777b5dc8262c675bf23c8dc5acfe8c4fa1ca8acdd956cdcbdf1fb2' +
21 'f879b37dc0ed8ec51815ff02b98eefde44ac79f886902ea69e5ed2561e9e' +
22 'eb2a74ec1de677b285f8108f25e9f34cc826fbbd1ad091d231dc73eaf28a' +
23 'e02f09ad84ec9a38d8a7e28bea26fb7d4db20eecd075b5b261ca7320af94' +
24 'cd58ba4b26d895df4fd6f68bd4d82acdcb35557012e2f69739ce8cf4a66e' +
25 'bf4550ee50f6c9cec642d66fef71495a';
26 
27export const rsaSignVerifyObjects = {
28 test(_, env) {
29 const key = createPrivateKey(env['rsa_private.pem']);
30 
31 throws(() => createSign(), {
32 message:
33 'The "algorithm" argument must be of type string. Received undefined',
34 });
35 
36 const signer = createSign('sha256');
37 signer.update('hello world');
38 
39 throws(() => signer.update(1), {
40 message: /argument must be of type string/,
41 });
42 
43 throws(() => signer.sign(), {
44 message: 'No key provided to sign',
45 });
46 
47 throws(() => signer.sign(env['rsa_public.pem']), {
48 message: 'Failed to parse private key',
49 });
50 
51 const pub = createPublicKey(env['rsa_public.pem']);
52 throws(() => signer.sign(pub), {
53 code: 'ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE',
54 });
55 
56 const signature = signer.sign(key, 'hex');
57 
58 throws(() => signer.sign(key, 'hex'), {
59 message: 'Signing context has already been finalized',
60 });
61 
62 strictEqual(signature, rsaSig);
63 
64 const verify = createVerify('sha256');
65 
66 throws(() => createVerify(), {
67 message:
68 'The "algorithm" argument must be of type string. Received undefined',
69 });
70 
71 verify.update('hello world');
72 
73 throws(() => verify.update(1), {
74 message: /argument must be of type string/,
75 });
76 
77 throws(() => verify.verify(), {
78 message: 'No key provided to sign',
79 });
80 
81 strictEqual(verify.verify(env['rsa_public.pem'], signature, 'hex'), true);
82 
83 throws(() => verify.verify(env['rsa_public.pem'], signature, 'hex'), {
84 message: 'Verification context has already been finalized',
85 });
86 },
87};
88 
89export const rsaSignVerifyOneshot = {
90 test(_, env) {
91 const key = createPrivateKey(env['rsa_private.pem']);
92 const sig = sign('sha256', Buffer.from('hello world'), key);
93 strictEqual(sig.toString('hex'), rsaSig);
94 strictEqual(
95 verify('sha256', Buffer.from('hello world'), env['rsa_public.pem'], sig),
96 true
97 );
98 },
99};
100 
101export const ed25519SignVerifyObjects = {
102 test(_, env) {
103 // Sign object is not allowed with ed25519
104 throws(
105 () => {
106 const key = createPrivateKey(env['ed25519_private.pem']);
107 const signer = createSign('sha256');
108 signer.update('hello world');
109 const _signature = signer.sign(key, 'hex');
110 },
111 {
112 message: 'Failed to set signature digest',
113 }
114 );
115 },
116};
117 
118export const ed25519SignVerifyOneshot = {
119 test(_, env) {
120 const key = createPrivateKey(env['ed25519_private.pem']);
121 const sig = sign(null, Buffer.from('hello world'), key);
122 strictEqual(
123 verify(null, Buffer.from('hello world'), env['ed25519_public.pem'], sig),
124 true
125 );
126 },
127};
128 
129export const dsaSignVerifyObjects = {
130 test(_, env) {
131 const pvt = createPrivateKey(env['dsa_private.pem']);
132 const pub = createPublicKey(env['dsa_public.pem']);
133 const signer = createSign('sha256');
134 const verifier = createVerify('sha256');
135 signer.update('');
136 verifier.update('');
137 throws(() => signer.sign(pvt), {
138 message: 'Signing with DSA keys is not currently supported',
139 });
140 throws(() => verifier.verify(pub, Buffer.alloc(0)), {
141 message: 'Verifying with DSA keys is not currently supported',
142 });
143 throws(() => sign('sha256', Buffer.alloc(0), pvt), {
144 message: 'Signing with DSA keys is not currently supported',
145 });
146 throws(() => verify('sha256', Buffer.alloc(0), pub, Buffer.alloc(0)), {
147 message: 'Verifying with DSA keys is not currently supported',
148 });
149 },
150};
151 
152export const testSignLength = {
153 test() {
154 // Tests that generated signatures are not overly long.
155 const message = `Test message 123: ${Math.random().toString(36).substring(2, 15)}`;
156 
157 const keyPair = generateKeyPairSync('ec', {
158 namedCurve: 'prime256v1',
159 publicKeyEncoding: {
160 type: 'spki',
161 format: 'pem',
162 },
163 privateKeyEncoding: {
164 type: 'pkcs8',
165 format: 'pem',
166 },
167 });
168 
169 for (let n = 0; n < 1000; n++) {
170 const sign = createSign('SHA256');
171 sign.write(Buffer.from(message));
172 sign.end();
173 
174 const sig = sign.sign(keyPair.privateKey);
175 
176 const verify = createVerify('SHA256');
177 verify.write(Buffer.from(message));
178 verify.end();
179 
180 // It will only verify correctly if the signature is the correct length.
181 ok(verify.verify(keyPair.publicKey, sig));
182 }
183 },
184};
185 
186// Test that Web Crypto keys (from crypto.subtle) can be used with
187// Node.js crypto sign/verify one-shot functions.
188export const webCryptoKeySignVerify = {
189 async test() {
190 const keyPair = await crypto.subtle.generateKey(
191 { name: 'ECDSA', namedCurve: 'P-256' },
192 true,
193 ['sign', 'verify']
194 );
195 const data = Buffer.from('hello world');
196 const sig = sign('SHA256', data, keyPair.privateKey);
197 ok(sig instanceof Buffer);
198 ok(sig.length > 0);
199 ok(verify('SHA256', data, keyPair.publicKey, sig));
200 },
201};
202 
203export const webCryptoKeySignVerifyP384 = {
204 async test() {
205 const keyPair = await crypto.subtle.generateKey(
206 { name: 'ECDSA', namedCurve: 'P-384' },
207 true,
208 ['sign', 'verify']
209 );
210 const data = Buffer.from('test data');
211 const sig = sign('SHA384', data, keyPair.privateKey);
212 ok(sig instanceof Buffer);
213 ok(sig.length > 0);
214 ok(verify('SHA384', data, keyPair.publicKey, sig));
215 },
216};