Skip to content

Commit e3ce818

Browse files
committed
add Finished
1 parent ef7d0f7 commit e3ce818

File tree

7 files changed

+116
-24
lines changed

7 files changed

+116
-24
lines changed

deno.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@tls/enum",
3-
"version": "0.3.6",
3+
"version": "0.3.7",
44
"exports": "./src/mod.ts",
55
"publish": {
66
"exclude": ["dist/"]
@@ -17,6 +17,7 @@
1717
"@noble/hashes": "npm:@noble/hashes@^1.6.1",
1818
"@peculiar/x509": "npm:@peculiar/x509@^1.12.3",
1919
"@std/assert": "jsr:@std/assert@^1.0.2",
20+
"@tls/crypto": "jsr:@tls/crypto@^0.0.9",
2021
"@tls/struct": "jsr:@tls/struct@^0.3.1"
2122
}
2223
}

src/dep.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ export * as utils from "@noble/curves/abstract/utils"
88
export { HexaDecimal } from "@tls/struct"
99
export * as x509 from "@peculiar/x509"
1010
export * from "@noble/hashes/sha2"
11+
export * from "@tls/crypto"
1112

src/handshaketype.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ export class Handshake extends Uint8Array {
127127
this.message = message
128128
this.items = struct.items
129129
}
130+
get byte(){ return Uint8Array.from(this)}
130131
}
131132

132133
// npx -p typescript tsc ./src/handshaketype.js --declaration --allowJs --emitDeclarationOnly --lib ESNext --outDir ./dist

src/signaturescheme.js

Lines changed: 69 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import { Constrained, Struct, Uint16 } from "./dep.ts";
55
import { Enum } from "./enum.js";
66
import { sha256 } from "@noble/hashes/sha256"
7+
import { hkdfExpandLabel } from "./dep.ts"
8+
import { HandshakeType } from "./handshaketype.js";
79

810
/**
911
* Enumeration of signature schemes as defined in RFC 8446.
@@ -79,6 +81,10 @@ export class SignatureScheme extends Enum {
7981
const signature = await signatureFrom(clientHelloMsg, serverHelloMsg, certificateMsg, RSAprivateKey)
8082
return new CertificateVerify(this, signature)
8183
}
84+
async certificateVerifyMsg(clientHelloMsg, serverHelloMsg, certificateMsg, RSAprivateKey){
85+
const certificateVerify = await this.certificateVerify(clientHelloMsg, serverHelloMsg, certificateMsg, RSAprivateKey);
86+
return HandshakeType.CERTIFICATE_VERIFY.handshake(certificateVerify);
87+
}
8288
}
8389

8490
export class CertificateVerify extends Uint8Array {
@@ -101,44 +107,44 @@ export class CertificateVerify extends Uint8Array {
101107
}
102108

103109
export class Signature extends Constrained {
104-
static from(array){
110+
static from(array) {
105111
const copy = Uint8Array.from(array);
106112
const lengthOf = Uint16.from(copy).value;
107113
return new Signature(copy.subarray(2, 2 + lengthOf))
108114
}
109-
constructor(opaque){
110-
super(0,2**16-1, opaque)
115+
constructor(opaque) {
116+
super(0, 2 ** 16 - 1, opaque)
111117
this.opaque = opaque
112118
}
113119
}
114120

115121
async function signatureFrom(clientHelloMsg, serverHelloMsg, certificateMsg, RSAprivateKey) {
116122
const leading = Uint8Array.of(
117-
//NOTE 64 space characters
118-
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,
119-
//NOTE 'TLS 1.3, server CertificateVerify'
120-
84, 76, 83, 32, 49, 46, 51, 44, 32, 115, 101, 114, 118, 101, 114, 32, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 86, 101, 114, 105, 102, 121,
121-
//NOTE single null char
122-
0
123+
//NOTE 64 space characters
124+
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,
125+
//NOTE 'TLS 1.3, server CertificateVerify'
126+
84, 76, 83, 32, 49, 46, 51, 44, 32, 115, 101, 114, 118, 101, 114, 32, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 86, 101, 114, 105, 102, 121,
127+
//NOTE single null char
128+
0
123129
)
124130
const transcriptHash = sha256.create()
125-
.update(clientHelloMsg)
126-
.update(serverHelloMsg)
127-
.update(certificateMsg)
128-
.digest();
131+
.update(clientHelloMsg)
132+
.update(serverHelloMsg)
133+
.update(certificateMsg)
134+
.digest();
129135

130136
const data = Struct.createFrom(
131-
leading,
132-
transcriptHash
137+
leading,
138+
transcriptHash
133139
)
134140

135141
const signBuffer = await crypto.subtle.sign(
136-
{
137-
name: "RSA-PSS",// RSAprivateKey.algorithm.name,
138-
saltLength: 256 / 8
139-
},
140-
RSAprivateKey,
141-
data
142+
{
143+
name: "RSA-PSS",// RSAprivateKey.algorithm.name,
144+
saltLength: 256 / 8
145+
},
146+
RSAprivateKey,
147+
data
142148
)
143149

144150
/* const verify = await crypto.subtle.verify(
@@ -150,8 +156,49 @@ async function signatureFrom(clientHelloMsg, serverHelloMsg, certificateMsg, RSA
150156
sign,
151157
data
152158
) */
159+
const signature = new Uint8Array(signBuffer)
160+
signature.transcriptHash = transcriptHash;
161+
return signature
162+
}
153163

154-
return new Uint8Array(signBuffer)
164+
export async function finished(serverHS_secret, certificateVerifyMsg) {
165+
const finishedKey = hkdfExpandLabel(serverHS_secret, 'finished', new Uint8Array, 32);
166+
const finishedKeyCrypto = await crypto.subtle.importKey(
167+
"raw",
168+
finishedKey,
169+
{
170+
name: "HMAC",
171+
hash: { name: "SHA-256" },
172+
},
173+
true,
174+
["sign", "verify"]
175+
);
176+
const transcriptHash = sha256.create()
177+
.update(certificateVerifyMsg.message.signature.transcriptHash)
178+
.update(certificateVerifyMsg.byte)
179+
.digest();
180+
181+
const verify_data = await crypto.subtle.sign(
182+
{ name: "HMAC" },
183+
finishedKeyCrypto,
184+
transcriptHash
185+
)
186+
187+
/* const _test_verify_data = await crypto.subtle.verify(
188+
{ name: "HMAC" },
189+
finishedKeyCrypto,
190+
verify_data,
191+
transcriptHash
192+
) */
193+
verify_data.transcriptHash = transcriptHash;
194+
return new Finished(verify_data);
195+
}
196+
197+
export class Finished extends Uint8Array {
198+
constructor(verify_data){
199+
super(verify_data);
200+
this.verify_data = verify_data
201+
}
155202
}
156203

157204
// npx -p typescript tsc ./src/signaturescheme.js --declaration --allowJs --emitDeclarationOnly --lib ESNext --outDir ./dist

test/signaturescheme_test.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { SignatureScheme, CertificateVerify } from "../src/signaturescheme.js";
1+
import { SignatureScheme, CertificateVerify, finished, Finished } from "../src/signaturescheme.js";
22
import { assertEquals } from "jsr:@std/assert";
33
import { HexaDecimal, sha256 } from "../src/dep.ts";
44

@@ -76,3 +76,14 @@ Deno.test("CertificateVerify", async () => {
7676
const back = CertificateVerify.from(test)
7777
assertEquals(test.toString(), back.toString())
7878
})
79+
80+
81+
Deno.test("Finished", async ()=>{
82+
const test = await SignatureScheme.RSA_PSS_PSS_SHA256.certificateVerifyMsg(clientHelloMsg, serverHelloMsg, certificateMsg, rsaKey.privateKey)
83+
//const back = CertificateVerify.from(test)
84+
const serverHS_secret_fake = crypto.getRandomValues(new Uint8Array(32));
85+
const _finished = await finished(serverHS_secret_fake, test);
86+
const finishedBack = Finished.from(_finished);
87+
assertEquals(_finished.toString(), finishedBack.toString())
88+
})
89+

type/handshaketype.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,4 +126,6 @@ export declare class Handshake extends Uint8Array {
126126
* @param message - The handshake message payload.
127127
*/
128128
constructor(msg_type: HandshakeType, message: Uint8Array);
129+
/** return Uint8Array */
130+
get byte(): Uint8Array
129131
}

type/signaturescheme.d.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,3 +136,32 @@ export function signatureFrom(
136136
certificateMsg: Uint8Array,
137137
RSAprivateKey: CryptoKey
138138
): Promise<Uint8Array>;
139+
140+
/**
141+
* Verifies and generates the HMAC for the given data.
142+
*
143+
* @param {Uint8Array} serverHS_secret - The server handshake secret used for key derivation.
144+
* @param {object} certificateVerifyMsg - The certificate verify message object.
145+
* @param {Uint8Array} certificateVerifyMsg.message.transcriptHash - The transcript hash from the message.
146+
* @returns {Promise<Uint8Array>} A promise that resolves to the verify_data HMAC value as a Uint8Array.
147+
*/
148+
export declare function finished(
149+
serverHS_secret: Uint8Array,
150+
certificateVerifyMsg: {
151+
message: {
152+
transcriptHash: Uint8Array;
153+
};
154+
}
155+
): Promise<Uint8Array>;
156+
157+
/**
158+
* Represents the Finished message as a Uint8Array.
159+
*/
160+
export declare class Finished extends Uint8Array {
161+
/**
162+
* Creates a Finished message instance.
163+
*
164+
* @param {Uint8Array} verify_data - The verify_data HMAC value.
165+
*/
166+
constructor(verify_data: Uint8Array);
167+
}

0 commit comments

Comments
 (0)