Skip to content

Commit 82d622b

Browse files
committed
rev signaturescheme
1 parent b39c91f commit 82d622b

File tree

4 files changed

+137
-76
lines changed

4 files changed

+137
-76
lines changed

deno.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@tls/enum",
3-
"version": "0.4.5",
3+
"version": "0.4.6",
44
"exports": "./src/mod.ts",
55
"publish": {
66
"exclude": ["dist/"]

src/signaturescheme.js

Lines changed: 62 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,43 @@ export class SignatureScheme extends Enum {
7676
*/
7777
get Uint16() { return Uint16.fromValue(+this); }
7878

79-
async certificateVerify(clientHelloMsg, serverHelloMsg, encryptedExtensionsMsg, certificateMsg, RSAprivateKey, sha) {
80-
const signature = await signatureFrom(clientHelloMsg, serverHelloMsg, encryptedExtensionsMsg, certificateMsg, RSAprivateKey, sha)
79+
get algo() {
80+
switch (this) {
81+
case 'ECDSA_SECP256R1_SHA256': return {
82+
name: "ECDSA",
83+
hash: "SHA-256"
84+
}
85+
case 'ECDSA_SECP384R1_SHA384': return {
86+
name: "ECDSA",
87+
hash: "SHA-384"
88+
}
89+
case 'ECDSA_SECP521R1_SHA512': return {
90+
name: "ECDSA",
91+
hash: "SHA-512"
92+
}
93+
case 'ED25519': return { name: 'Ed25519' }
94+
case 'RSA_PSS_PSS_SHA384': return {
95+
name: "RSA-PSS",// RSAprivateKey.algorithm.name,
96+
saltLength: 384 / 8
97+
}
98+
case 'RSA_PSS_PSS_SHA512': return {
99+
name: "RSA-PSS",// RSAprivateKey.algorithm.name,
100+
saltLength: 512 / 8
101+
}
102+
case 'RSA_PSS_PSS_SHA256':
103+
default: return {
104+
name: "RSA-PSS",// RSAprivateKey.algorithm.name,
105+
saltLength: 256 / 8
106+
}
107+
}
108+
return {
109+
name: "RSA-PSS",// RSAprivateKey.algorithm.name,
110+
saltLength: 256 / 8
111+
}
112+
}
113+
114+
async certificateVerify(clientHelloMsg, serverHelloMsg, encryptedExtensionsMsg, certificateMsg, RSAprivateKey) {
115+
const signature = await signatureFrom(clientHelloMsg, serverHelloMsg, encryptedExtensionsMsg, certificateMsg, RSAprivateKey, this.algo)
81116
return new CertificateVerify(this, signature)
82117
}
83118
}
@@ -114,7 +149,7 @@ export class Signature extends Constrained {
114149
}
115150
}
116151

117-
async function signatureFrom(clientHelloMsg, serverHelloMsg, encryptedExtensionsMsg, certificateMsg, RSAprivateKey, sha = 256) {
152+
async function signatureFrom(clientHelloMsg, serverHelloMsg, encryptedExtensionsMsg, certificateMsg, RSAprivateKey, algo) {
118153
const leading = Uint8Array.of(
119154
//NOTE 64 space characters
120155
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
@@ -124,10 +159,8 @@ async function signatureFrom(clientHelloMsg, serverHelloMsg, encryptedExtensions
124159
0
125160
)
126161

127-
const hash = sha == 256 ? sha256.create() :
128-
sha == 384 ? sha384.create() :
129-
sha == 512 ? sha512.create() : sha256.create();
130-
162+
const hash = hashFromAlgo(algo)
163+
131164
const transcriptHash = hash
132165
.update(clientHelloMsg)
133166
.update(serverHelloMsg)
@@ -141,10 +174,7 @@ async function signatureFrom(clientHelloMsg, serverHelloMsg, encryptedExtensions
141174
)
142175

143176
const signBuffer = await crypto.subtle.sign(
144-
{
145-
name: "RSA-PSS",// RSAprivateKey.algorithm.name,
146-
saltLength: sha / 8
147-
},
177+
algo,
148178
RSAprivateKey,
149179
data
150180
)
@@ -161,6 +191,21 @@ async function signatureFrom(clientHelloMsg, serverHelloMsg, encryptedExtensions
161191
return new Uint8Array(signBuffer)
162192
}
163193

194+
function hashFromAlgo(algo) {
195+
let sha
196+
const { hash, saltLength } = algo;
197+
if (hash) { sha = parseInt(hash.split("-")[1]); }
198+
else if (saltLength) { sha = saltLength * 8 }
199+
else { sha = 256 };
200+
switch (sha) {
201+
case 384: return sha384.create();
202+
case 512: return sha512.create();
203+
case 256:
204+
default:
205+
return sha256.create();
206+
}
207+
}
208+
164209
export async function finished(finishedKey, sha = 256, ...messages) {
165210
//const finishedKey = hkdfExpandLabel(serverHS_secret, 'finished', new Uint8Array, 32);
166211
const finishedKeyCrypto = await crypto.subtle.importKey(
@@ -174,8 +219,8 @@ export async function finished(finishedKey, sha = 256, ...messages) {
174219
["sign", "verify"]
175220
);
176221

177-
const hash = sha == 256 ? sha256.create() :
178-
sha == 384 ? sha384.create() : sha256.create();
222+
const hash = sha == 256 ? sha256.create() :
223+
sha == 384 ? sha384.create() : sha256.create();
179224

180225
const messagesStruct = Struct.createFrom(...messages);
181226

@@ -195,18 +240,18 @@ export async function finished(finishedKey, sha = 256, ...messages) {
195240
verify_data,
196241
transcriptHash
197242
) */
198-
verify_data.transcriptHash = transcriptHash;
243+
//verify_data.transcriptHash = transcriptHash;
199244
return new Finished(verify_data);
200245
}
201246

202247
export class Finished extends Uint8Array {
203-
static fromMsg(message){
248+
static fromMsg(message) {
204249
const copy = Uint8Array.from(message)
205250
return new Finished(copy.subarray(4))
206251
}
207-
constructor(verify_data){
252+
constructor(verify_data) {
208253
super(verify_data);
209-
this.verify_data = verify_data
254+
this.verify_data = verify_data
210255
return HandshakeType.FINISHED.handshake(this)
211256
}
212257
}

test/signaturescheme_test.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,36 @@ Deno.test("Finished", async () => {
9393
assertEquals(_finished.toString(), finishedBack.toString())
9494
})
9595

96+
const hash = "SHA-256";
97+
const sha = parseInt(hash.split("-")[1]);
98+
99+
const certificateVerifyMsg = HexaDecimal.fromString(`0f 00 00 84 08 04 00 80 5a 74 7c
100+
5d 88 fa 9b d2 e5 5a b0 85 a6 10 15 b7 21 1f 82 4c d4 84 14 5a
101+
b3 ff 52 f1 fd a8 47 7b 0b 7a bc 90 db 78 e2 d3 3a 5c 14 1a 07
102+
86 53 fa 6b ef 78 0c 5e a2 48 ee aa a7 85 c4 f3 94 ca b6 d3 0b
103+
be 8d 48 59 ee 51 1f 60 29 57 b1 54 11 ac 02 76 71 45 9e 46 44
104+
5c 9e a5 8c 18 1e 81 8e 95 b8 c3 fb 0b f3 27 84 09 d3 be 15 2a
105+
3d a5 04 3e 06 3d da 65 cd f5 ae a2 0d 53 df ac d4 2f 74 f3`).byte
106+
107+
const finishedMsg = HexaDecimal.fromString(
108+
`14 00 00 20 9b 9b 14 1d 90 63 37 fb d2 cb
109+
dc e7 1d f4 de da 4a b4 2c 30 95 72 cb 7f ff ee 54 54 b7 8f 07
110+
18`).byte
111+
112+
const rsaPrivateKeyJwk = JSON.parse('{"kty":"RSA","alg":"PS256","key_ops":["sign"],"ext":true,"n":"tLtJj4J5MD2YCDY5mzbGmIwMaN5V4b24JtOQGiRh6v0t5JqR0BWrvJqVE3rObBrxnqpq-Yx87UMSCZjhh6gO4MywUksbAYw-C2MmTUSabTjiKl_aQwhGdIAwUw7wRhyMqdnvv66OptHQPivRk-_wq5qAAsR0KKbTWo2I159_Hj8","e":"AQAB","d":"BN6nBdQ6bqcgndgHIRGoPIHjIqWSeLM0gGQer3wKaYW44xxE9t5i4bTCMJ9hJud7fEHpIzFLv6OIEwXcEhfxbIGc5TjpIvNpgo0OVxldjISIRgIHsvqnJrz3CLvX239nn4k0kvwqYi4IlwqsRBzk4MMIjfJa5nkjPfijvaL_mUE","p":"5DX7fMg3N3VtrOqWq39ZoswQadt96xkOF-M6UysnPzCjJ6oKqrxYzWdGavmEX63Gdf4JSvksS9Hywbwz3S4FFQ","q":"yr07wOBDhmTI1MyfmZd6lNm7_q2OQ4cKuuP364tODu6K8dm0cZumGWzyy7ru6_izSQr-np_6dKiKpR_GRWKTAw","dp":"P1c0XCf-G2h-bnYWJ7eLG4JkM912D6C-pqas85SQqhtHzaSGnWj1hN1bUCm9Mgk7glhmH-cVAl5dcKRaCNPTGQ","dq":"GD2gE2O9LyiFysvcmWS_R2TxUXY2-GQBKG9xiTxSzP5ApsI9DQhrR8b7ENj9EEHgTe9-mkDOlXxBd5ThBBLROQ","qi":"g5ypoIXkKGsskORmmXosaB8hM5qjR3gU5N7BGDMFDtUN0TzAOASKQ8WbKsxBaInAN2Zf5a-mBZafjAHfpcqWnQ"}');
113+
114+
const rsaPrivateKey = await crypto.subtle.importKey('jwk', rsaPrivateKeyJwk, { name: 'RSA-PSS', hash: 'SHA-256' }, true, ['sign'])
115+
116+
const certificateVerifyMsg_0 = await SignatureScheme.RSA_PSS_PSS_SHA256.certificateVerify(clientHelloMsg, serverHelloMsg, encryptedExtensionsMsg, certificateMsg, rsaPrivateKey)
117+
118+
const finished_key = HexaDecimal.fromString(
119+
`00 8d 3b 66 f8 16 ea 55 9f 96 b5 37 e8 85
120+
c3 1f c0 68 bf 49 2c 65 2f 01 f2 88 a1 d8 cd c1 9f c8`).byte
121+
122+
const finished_0 = await finished(finished_key, 256, clientHelloMsg, serverHelloMsg, encryptedExtensionsMsg, certificateMsg);
123+
124+
125+
debugger;
96126

97127

98128

type/signaturescheme.d.ts

Lines changed: 44 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,147 +1,133 @@
11
import { Constrained, Uint16 } from "../src/dep.ts";
22
import { Enum } from "../src/enum.js";
3+
import { sha256, sha384, sha512 } from "@noble/hashes/sha2";
34

45
/**
56
* Enumeration of signature schemes as defined in RFC 8446.
67
* @see https://datatracker.ietf.org/doc/html/rfc8446#section-4.2.3
78
*/
8-
export class SignatureScheme extends Enum {
9-
/** RSASSA-PKCS1-v1_5 algorithms */
9+
export declare class SignatureScheme extends Enum {
1010
static RSA_PKCS1_SHA256: SignatureScheme;
1111
static RSA_PKCS1_SHA384: SignatureScheme;
1212
static RSA_PKCS1_SHA512: SignatureScheme;
13-
14-
/** ECDSA algorithms */
1513
static ECDSA_SECP256R1_SHA256: SignatureScheme;
1614
static ECDSA_SECP384R1_SHA384: SignatureScheme;
1715
static ECDSA_SECP521R1_SHA512: SignatureScheme;
18-
19-
/** RSASSA-PSS algorithms with public key OID rsaEncryption */
2016
static RSA_PSS_RSAE_SHA256: SignatureScheme;
2117
static RSA_PSS_RSAE_SHA384: SignatureScheme;
2218
static RSA_PSS_RSAE_SHA512: SignatureScheme;
23-
24-
/** EdDSA algorithms */
2519
static ED25519: SignatureScheme;
2620
static ED448: SignatureScheme;
27-
28-
/** RSASSA-PSS algorithms with public key OID RSASSA-PSS */
2921
static RSA_PSS_PSS_SHA256: SignatureScheme;
3022
static RSA_PSS_PSS_SHA384: SignatureScheme;
3123
static RSA_PSS_PSS_SHA512: SignatureScheme;
32-
33-
/** Legacy algorithms */
3424
static RSA_PKCS1_SHA1: SignatureScheme;
3525
static ECDSA_SHA1: SignatureScheme;
36-
37-
/** Reserved Code Points */
3826
static dsa_sha1_RESERVED: SignatureScheme;
3927
static dsa_sha256_RESERVED: SignatureScheme;
4028
static dsa_sha384_RESERVED: SignatureScheme;
4129
static dsa_sha512_RESERVED: SignatureScheme;
4230

4331
/**
4432
* Parses an octet array and returns a valid SignatureScheme.
45-
* @param {Uint8Array} octet - The octet array to parse.
46-
* @returns {SignatureScheme} The corresponding SignatureScheme instance.
33+
* @param octet The octet array to parse.
34+
* @returns The corresponding SignatureScheme instance.
4735
* @throws {Error} If the octet does not correspond to a known SignatureScheme.
4836
*/
4937
static from(octet: Uint8Array): SignatureScheme;
5038

5139
/**
52-
* Returns the bit length of the SignatureScheme.
53-
* @returns {number} The bit length, which is always 16.
40+
* The bit length of the SignatureScheme.
41+
* @returns The bit length, which is always 16.
5442
*/
5543
get bit(): number;
5644

5745
/**
5846
* Converts the SignatureScheme to a Uint16 representation.
59-
* @returns {Uint16} The Uint16 representation of the SignatureScheme.
47+
* @returns The Uint16 representation of the SignatureScheme.
6048
*/
6149
get Uint16(): Uint16;
6250

6351
/**
64-
* Creates a CertificateVerify handshake instance.
65-
* @param clientHelloMsg The ClientHello message.
66-
* @param serverHelloMsg The ServerHello message.
67-
* @param encryptedExtensionsMsg The EncryptedExtensions message.
68-
* @param certificateMsg The Certificate message.
69-
* @param RSAprivateKey The RSA private key.
70-
* @param sha The SHA variant (256, 384, or 512).
52+
* Retrieves the algorithm details for the SignatureScheme.
53+
* @returns An object describing the algorithm and hash details.
54+
*/
55+
get algo(): { name: string; hash?: string; saltLength?: number };
56+
57+
/**
58+
* Verifies a certificate using the provided messages and private key.
59+
* @param clientHelloMsg The client hello message.
60+
* @param serverHelloMsg The server hello message.
61+
* @param encryptedExtensionsMsg The encrypted extensions message.
62+
* @param certificateMsg The certificate message.
63+
* @param RSAprivateKey The private RSA key.
64+
* @returns A promise that resolves to a CertificateVerify instance.
7165
*/
7266
certificateVerify(
7367
clientHelloMsg: Uint8Array,
7468
serverHelloMsg: Uint8Array,
7569
encryptedExtensionsMsg: Uint8Array,
7670
certificateMsg: Uint8Array,
77-
RSAprivateKey: CryptoKey,
78-
sha: number,
71+
RSAprivateKey: CryptoKey
7972
): Promise<CertificateVerify>;
8073
}
8174

82-
/**
83-
* Represents a CertificateVerify message.
84-
*/
8575
export declare class CertificateVerify extends Uint8Array {
86-
/**
87-
* Creates a CertificateVerify instance from an array.
88-
* @param array The input array.
89-
*/
9076
static fromMsg(array: Uint8Array): CertificateVerify;
91-
9277
constructor(signatureScheme: SignatureScheme, signature: Uint8Array);
93-
9478
algorithm: SignatureScheme;
9579
signature: Uint8Array;
9680
}
9781

98-
/**
99-
* Represents a constrained Signature.
100-
*/
10182
export declare class Signature extends Constrained {
102-
/**
103-
* Creates a Signature instance from an array.
104-
* @param array The input array.
105-
*/
10683
static from(array: Uint8Array): Signature;
107-
10884
constructor(opaque: Uint8Array);
109-
11085
opaque: Uint8Array;
11186
}
11287

11388
/**
114-
* Generates a signature for the CertificateVerify message.
89+
* Generates a signature from the provided messages and key.
90+
* @param clientHelloMsg The client hello message.
91+
* @param serverHelloMsg The server hello message.
92+
* @param encryptedExtensionsMsg The encrypted extensions message.
93+
* @param certificateMsg The certificate message.
94+
* @param RSAprivateKey The private RSA key.
95+
* @param algo The algorithm to use for signing.
96+
* @returns A promise that resolves to the generated signature as a Uint8Array.
11597
*/
11698
export declare function signatureFrom(
11799
clientHelloMsg: Uint8Array,
118100
serverHelloMsg: Uint8Array,
119101
encryptedExtensionsMsg: Uint8Array,
120102
certificateMsg: Uint8Array,
121103
RSAprivateKey: CryptoKey,
122-
sha?: number,
104+
algo: { name: string; hash?: string; saltLength?: number }
123105
): Promise<Uint8Array>;
124106

125107
/**
126-
* Generates a Finished message.
108+
* Computes the hash function based on the provided algorithm.
109+
* @param algo The algorithm details.
110+
* @returns The appropriate hash instance.
111+
*/
112+
export declare function hashFromAlgo(
113+
algo: { hash?: string; saltLength?: number }
114+
): ReturnType<typeof sha256.create | typeof sha384.create | typeof sha512.create>;
115+
116+
/**
117+
* Creates a Finished instance from the provided key and messages.
118+
* @param finishedKey The HMAC key used for the finished computation.
119+
* @param sha The SHA variant to use (256, 384, etc.).
120+
* @param messages The messages to include in the transcript.
121+
* @returns A promise that resolves to a Finished instance.
127122
*/
128123
export declare function finished(
129124
finishedKey: Uint8Array,
130125
sha: number,
131126
...messages: Uint8Array[]
132127
): Promise<Finished>;
133128

134-
/**
135-
* Represents a Finished handshake message.
136-
*/
137129
export declare class Finished extends Uint8Array {
138-
/**
139-
* Creates a Finished instance from a message.
140-
* @param message The input message.
141-
*/
142130
static fromMsg(message: Uint8Array): Finished;
143-
144131
constructor(verify_data: Uint8Array);
145-
146132
verify_data: Uint8Array;
147133
}

0 commit comments

Comments
 (0)