diff --git a/packages/core/src/__tests__/asn1/length.test.ts b/packages/core/src/__tests__/asn1/length.test.ts index bc28f315f..7cb8f904f 100644 --- a/packages/core/src/__tests__/asn1/length.test.ts +++ b/packages/core/src/__tests__/asn1/length.test.ts @@ -62,31 +62,31 @@ describe('decodeLength', () => { describe('encodeLength', () => { describe('when the length is less than 128', () => { it('returns the encoded length', () => { - expect(encodeLength(16)).toEqual(Buffer.from([0x10])); + expect(encodeLength(16)).toEqual(new Uint8Array([0x10])); }); }); describe('when the length is equal to 128', () => { it('returns the encoded length', () => { - expect(encodeLength(128)).toEqual(Buffer.from([0x81, 0x80])); + expect(encodeLength(128)).toEqual(new Uint8Array([0x81, 0x80])); }); }); describe('when the length is greater than 128', () => { it('returns the encoded length', () => { - expect(encodeLength(256)).toEqual(Buffer.from([0x82, 0x01, 0x00])); + expect(encodeLength(256)).toEqual(new Uint8Array([0x82, 0x01, 0x00])); }); }); describe('when the length is the max value', () => { it('returns the encoded length', () => { expect(encodeLength(281474976710655)).toEqual( - Buffer.from([0x86, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]) + new Uint8Array([0x86, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]) ); }); }); }); function streamFromBytes(bytes: number[]): ByteStream { - return new ByteStream(Buffer.from(bytes)); + return new ByteStream(new Uint8Array(bytes)); } diff --git a/packages/core/src/__tests__/asn1/obj.test.ts b/packages/core/src/__tests__/asn1/obj.test.ts index 69b8dff0a..eb6d7d1fc 100644 --- a/packages/core/src/__tests__/asn1/obj.test.ts +++ b/packages/core/src/__tests__/asn1/obj.test.ts @@ -15,19 +15,20 @@ limitations under the License. */ import { ASN1TypeError } from '../../asn1/error'; import { ASN1Obj } from '../../asn1/obj'; +import { uint8ArrayToHex, hexToUint8Array } from '../../encoding'; describe('ASN1Obj', () => { describe('parseBuffer', () => { describe('when parsing a primitive', () => { // INTEGER (2 bytes) 0x1010 - const buffer = Buffer.from('02021010', 'hex'); + const buffer = hexToUint8Array('02021010'); it('parses a primitive', () => { const obj = ASN1Obj.parseBuffer(buffer); expect(obj).toBeInstanceOf(ASN1Obj); expect(obj.tag.number).toBe(2); - expect(obj.value.toString('hex')).toBe('1010'); + expect(uint8ArrayToHex(obj.value)).toBe('1010'); expect(obj.subs).toHaveLength(0); expect(obj.toDER()).toEqual(buffer); @@ -38,24 +39,24 @@ describe('ASN1Obj', () => { // SEQUENCE (8 bytes) // INTEGER (2 bytes) 0x1010 // INTEGER (2 bytes) 0x1111 - const buffer = Buffer.from('30080202101002021111', 'hex'); + const buffer = hexToUint8Array('30080202101002021111'); it('parses a constructed object', () => { const obj = ASN1Obj.parseBuffer(buffer); expect(obj).toBeInstanceOf(ASN1Obj); expect(obj.tag.constructed).toBe(true); expect(obj.tag.number).toBe(16); - expect(obj.value.toString('hex')).toBe('0202101002021111'); + expect(uint8ArrayToHex(obj.value)).toBe('0202101002021111'); expect(obj.subs).toHaveLength(2); expect(obj.subs[0].tag.constructed).toBe(false); expect(obj.subs[0].tag.number).toBe(2); - expect(obj.subs[0].value.toString('hex')).toBe('1010'); + expect(uint8ArrayToHex(obj.subs[0].value)).toBe('1010'); expect(obj.subs[0].subs).toHaveLength(0); expect(obj.subs[1].tag.constructed).toBe(false); expect(obj.subs[1].tag.number).toBe(2); - expect(obj.subs[1].value.toString('hex')).toBe('1111'); + expect(uint8ArrayToHex(obj.subs[1].value)).toBe('1111'); expect(obj.subs[1].subs).toHaveLength(0); }); }); @@ -64,24 +65,24 @@ describe('ASN1Obj', () => { // OCTET STRING (8 bytes) // INTEGER (2 bytes) 0x1010 // INTEGER (2 bytes) 0x1010 - const buffer = Buffer.from('04080202101002021111', 'hex'); + const buffer = hexToUint8Array('04080202101002021111'); it('parses the object', () => { const obj = ASN1Obj.parseBuffer(buffer); expect(obj).toBeInstanceOf(ASN1Obj); expect(obj.tag.constructed).toBe(false); expect(obj.tag.number).toBe(0x04); - expect(obj.value.toString('hex')).toBe('0202101002021111'); + expect(uint8ArrayToHex(obj.value)).toBe('0202101002021111'); expect(obj.subs).toHaveLength(2); expect(obj.subs[0].tag.constructed).toBe(false); expect(obj.subs[0].tag.number).toBe(2); - expect(obj.subs[0].value.toString('hex')).toBe('1010'); + expect(uint8ArrayToHex(obj.subs[0].value)).toBe('1010'); expect(obj.subs[0].subs).toHaveLength(0); expect(obj.subs[1].tag.constructed).toBe(false); expect(obj.subs[1].tag.number).toBe(2); - expect(obj.subs[1].value.toString('hex')).toBe('1111'); + expect(uint8ArrayToHex(obj.subs[1].value)).toBe('1111'); expect(obj.subs[1].subs).toHaveLength(0); }); }); @@ -90,14 +91,14 @@ describe('ASN1Obj', () => { describe('when the OCTET STREAM value almost looks like an embedded obj', () => { // OCTET STREAM looks like it could have a nested OCTET STREAM, but it // doesn't -- the length of the nested OCTET STREAM is too long. - const buffer = Buffer.from('04020408', 'hex'); + const buffer = hexToUint8Array('04020408'); it('parses the OCTET STREAM as a primitive', () => { const obj = ASN1Obj.parseBuffer(buffer); expect(obj).toBeInstanceOf(ASN1Obj); expect(obj.tag.constructed).toBe(false); expect(obj.tag.number).toBe(0x04); - expect(obj.value.toString('hex')).toBe('0408'); + expect(uint8ArrayToHex(obj.value)).toBe('0408'); expect(obj.subs).toHaveLength(0); }); }); @@ -105,14 +106,14 @@ describe('ASN1Obj', () => { describe('when the OCTET STREAM value almost looks like an embedded obj', () => { // OCTET STREAM looks like it could have a nested OCTET STREAM, but it // doesn't -- the length of the nested OCTET STREAM is too short. - const buffer = Buffer.from('0406040213013131', 'hex'); + const buffer = hexToUint8Array('0406040213013131'); it('parses the OCTET STREAM as a primitive', () => { const obj = ASN1Obj.parseBuffer(buffer); expect(obj).toBeInstanceOf(ASN1Obj); expect(obj.tag.constructed).toBe(false); expect(obj.tag.number).toBe(0x04); - expect(obj.value.toString('hex')).toBe('040213013131'); + expect(uint8ArrayToHex(obj.value)).toBe('040213013131'); expect(obj.subs).toHaveLength(0); }); }); @@ -122,7 +123,7 @@ describe('ASN1Obj', () => { describe('#toDER', () => { describe('when the object is a primitive', () => { // INTEGER (2 bytes) 0x1010 - const buffer = Buffer.from('02021010', 'hex'); + const buffer = hexToUint8Array('02021010'); const obj = ASN1Obj.parseBuffer(buffer); it('encodes properly', () => { @@ -134,7 +135,7 @@ describe('ASN1Obj', () => { // SEQUENCE (8 bytes) // INTEGER (2 bytes) 0x1010 // INTEGER (2 bytes) 0x1111 - const buffer = Buffer.from('30080202101002021111', 'hex'); + const buffer = hexToUint8Array('30080202101002021111'); const obj = ASN1Obj.parseBuffer(buffer); it('encodes properly', () => { @@ -146,7 +147,7 @@ describe('ASN1Obj', () => { it('encodes properly', () => { obj.subs.splice(0, 1); - expect(obj.toDER()).toStrictEqual(Buffer.from('300402021111', 'hex')); + expect(obj.toDER()).toStrictEqual(hexToUint8Array('300402021111')); }); }); }); @@ -156,7 +157,7 @@ describe('ASN1Obj', () => { describe('when the object is a BOOLEAN', () => { describe('when the value is 0x00', () => { // BOOLEAN (1 byte) 0x00 - const buffer = Buffer.from('010100', 'hex'); + const buffer = hexToUint8Array('010100'); it('returns false', () => { const obj = ASN1Obj.parseBuffer(buffer); expect(obj.toBoolean()).toBe(false); @@ -165,7 +166,7 @@ describe('ASN1Obj', () => { describe('when the value is 0x01', () => { // BOOLEAN (1 byte) 0x01 - const buffer = Buffer.from('010101', 'hex'); + const buffer = hexToUint8Array('010101'); it('returns true', () => { const obj = ASN1Obj.parseBuffer(buffer); expect(obj.toBoolean()).toBe(true); @@ -174,7 +175,7 @@ describe('ASN1Obj', () => { }); describe('when the object is not a BOOLEAN', () => { - const buffer = Buffer.from('810102', 'hex'); + const buffer = hexToUint8Array('810102'); it('throws an error', () => { const obj = ASN1Obj.parseBuffer(buffer); expect(() => obj.toBoolean()).toThrow(ASN1TypeError); @@ -185,7 +186,7 @@ describe('ASN1Obj', () => { describe('#toInteger', () => { describe('when the object is an INTEGER', () => { // INTEGER (1 bytes) 0x00 - const buffer = Buffer.from('020100', 'hex'); + const buffer = hexToUint8Array('020100'); it('returns the parsed integer', () => { const obj = ASN1Obj.parseBuffer(buffer); expect(obj.toInteger()).toBe(BigInt(0)); @@ -193,7 +194,7 @@ describe('ASN1Obj', () => { }); describe('when the object is NOT an INTEGER', () => { - const buffer = Buffer.from('820100', 'hex'); + const buffer = hexToUint8Array('820100'); it('throws an error', () => { const obj = ASN1Obj.parseBuffer(buffer); expect(() => obj.toInteger()).toThrow(ASN1TypeError); @@ -204,7 +205,7 @@ describe('ASN1Obj', () => { describe('#toOID', () => { describe('when the object is an OBJECT IDENTIFIER', () => { // OBJECT IDENTIFIER (1 byte) 0x82 - const buffer = Buffer.from('060182', 'hex'); + const buffer = hexToUint8Array('060182'); it('returns parsed OID', () => { const obj = ASN1Obj.parseBuffer(buffer); expect(obj.toOID()).toBe('3.10'); @@ -212,7 +213,7 @@ describe('ASN1Obj', () => { }); describe('when the object is NOT an OBJECT IDENTIFIER', () => { - const buffer = Buffer.from('020100', 'hex'); + const buffer = hexToUint8Array('020100'); it('throws an error', () => { const obj = ASN1Obj.parseBuffer(buffer); expect(() => obj.toOID()).toThrow(ASN1TypeError); @@ -223,7 +224,7 @@ describe('ASN1Obj', () => { describe('#toDate', () => { describe('when the object is a UTCTime', () => { // UTCTime (13 bytes) 0x3232313132323131313131315A - const buffer = Buffer.from('170D3232313132323131313131315A', 'hex'); + const buffer = hexToUint8Array('170D3232313132323131313131315A'); it('returns the parsed date', () => { const obj = ASN1Obj.parseBuffer(buffer); expect(obj.toDate().toISOString()).toBe('2022-11-22T11:11:11.000Z'); @@ -232,7 +233,7 @@ describe('ASN1Obj', () => { describe('when the object is a GeneralizedTime', () => { // GeneralizedTime (15 bytes) 0x32303232313132323131313131315A - const buffer = Buffer.from('180F32303232313132323131313131315A', 'hex'); + const buffer = hexToUint8Array('180F32303232313132323131313131315A'); it('returns the parsed date', () => { const obj = ASN1Obj.parseBuffer(buffer); expect(obj.toDate().toISOString()).toBe('2022-11-22T11:11:11.000Z'); @@ -240,7 +241,7 @@ describe('ASN1Obj', () => { }); describe('when the object is NOT an UTCTime or GeneralizedTime', () => { - const buffer = Buffer.from('020100', 'hex'); + const buffer = hexToUint8Array('020100'); it('throws an error', () => { const obj = ASN1Obj.parseBuffer(buffer); expect(() => obj.toDate()).toThrow(ASN1TypeError); @@ -251,7 +252,7 @@ describe('ASN1Obj', () => { describe('#toBitString', () => { describe('when the object is a BITSTRING', () => { // BITSTRING (2 bytes) 0x00F0 - const buffer = Buffer.from('030200F0', 'hex'); + const buffer = hexToUint8Array('030200F0'); it('returns the parsed bit string', () => { const obj = ASN1Obj.parseBuffer(buffer); expect(obj.toBitString()).toEqual([1, 1, 1, 1, 0, 0, 0, 0]); @@ -259,7 +260,7 @@ describe('ASN1Obj', () => { }); describe('when the object is NOT a BITSTRING', () => { - const buffer = Buffer.from('020100', 'hex'); + const buffer = hexToUint8Array('020100'); it('throws an error', () => { const obj = ASN1Obj.parseBuffer(buffer); expect(() => obj.toBitString()).toThrow(ASN1TypeError); diff --git a/packages/core/src/__tests__/asn1/parse.test.ts b/packages/core/src/__tests__/asn1/parse.test.ts index f4ccc8db1..807f6d6e1 100644 --- a/packages/core/src/__tests__/asn1/parse.test.ts +++ b/packages/core/src/__tests__/asn1/parse.test.ts @@ -21,26 +21,27 @@ import { parseStringASCII, parseTime, } from '../../asn1/parse'; +import { hexToUint8Array, stringToUint8Array } from '../../encoding'; describe('parseInteger', () => { it('parses positive integers', () => { - expect(parseInteger(Buffer.from([0x00]))).toEqual(BigInt(0)); - expect(parseInteger(Buffer.from([0x7f]))).toEqual(BigInt(127)); - expect(parseInteger(Buffer.from([0x00, 0x80]))).toEqual(BigInt(128)); - expect(parseInteger(Buffer.from([0x01, 0x00]))).toEqual(BigInt(256)); + expect(parseInteger(new Uint8Array([0x00]))).toEqual(BigInt(0)); + expect(parseInteger(new Uint8Array([0x7f]))).toEqual(BigInt(127)); + expect(parseInteger(new Uint8Array([0x00, 0x80]))).toEqual(BigInt(128)); + expect(parseInteger(new Uint8Array([0x01, 0x00]))).toEqual(BigInt(256)); }); it('parses negative integers', () => { - expect(parseInteger(Buffer.from([0xff]))).toEqual(BigInt(-1)); - expect(parseInteger(Buffer.from([0x80]))).toEqual(BigInt(-128)); - expect(parseInteger(Buffer.from([0xff, 0x7f]))).toEqual(BigInt(-129)); - expect(parseInteger(Buffer.from([0xff, 0x00]))).toEqual(BigInt(-256)); + expect(parseInteger(new Uint8Array([0xff]))).toEqual(BigInt(-1)); + expect(parseInteger(new Uint8Array([0x80]))).toEqual(BigInt(-128)); + expect(parseInteger(new Uint8Array([0xff, 0x7f]))).toEqual(BigInt(-129)); + expect(parseInteger(new Uint8Array([0xff, 0x00]))).toEqual(BigInt(-256)); }); }); describe('parseStringASCII', () => { it('parses ASCII strings', () => { - expect(parseStringASCII(Buffer.from([0x48, 0x69, 0x21]))).toEqual('Hi!'); + expect(parseStringASCII(new Uint8Array([0x48, 0x69, 0x21]))).toEqual('Hi!'); }); }); @@ -48,7 +49,7 @@ describe('parseTime', () => { describe('with short year', () => { describe('when year is 50 or greater', () => { it('parses the date', () => { - expect(parseTime(Buffer.from('740212121110Z'), true)).toEqual( + expect(parseTime(stringToUint8Array('740212121110Z'), true)).toEqual( new Date('1974-02-12T12:11:10Z') ); }); @@ -56,7 +57,7 @@ describe('parseTime', () => { describe('when year is less than 50', () => { it('parses the date', () => { - expect(parseTime(Buffer.from('180212121110.099Z'), true)).toEqual( + expect(parseTime(stringToUint8Array('180212121110.099Z'), true)).toEqual( new Date('2018-02-12T12:11:10Z') ); }); @@ -65,7 +66,7 @@ describe('parseTime', () => { describe('with long year', () => { it('parses the date', () => { - expect(parseTime(Buffer.from('19180212121110Z'), false)).toEqual( + expect(parseTime(stringToUint8Array('19180212121110Z'), false)).toEqual( new Date('1918-02-12T12:11:10Z') ); }); @@ -73,7 +74,7 @@ describe('parseTime', () => { describe('with long year and milliseconds', () => { it('parses the date', () => { - expect(parseTime(Buffer.from('19180212121110.099Z'), false)).toEqual( + expect(parseTime(stringToUint8Array('19180212121110.099Z'), false)).toEqual( new Date('1918-02-12T12:11:10Z') ); }); @@ -81,7 +82,7 @@ describe('parseTime', () => { describe('when the time is invalid', () => { it('throws an error', () => { - expect(() => parseTime(Buffer.from('FOOBAR'), true)).toThrow( + expect(() => parseTime(stringToUint8Array('FOOBAR'), true)).toThrow( 'invalid time' ); }); @@ -118,27 +119,27 @@ describe('parseOID', () => { it('parses OID strings', () => { tests.forEach(({ oid, expected }) => { - expect(parseOID(Buffer.from(oid, 'hex'))).toEqual(expected); + expect(parseOID(hexToUint8Array(oid))).toEqual(expected); }); }); }); describe('parseBoolean', () => { it('parses boolean values', () => { - expect(parseBoolean(Buffer.from([0x00]))).toEqual(false); - expect(parseBoolean(Buffer.from([0xff]))).toEqual(true); + expect(parseBoolean(new Uint8Array([0x00]))).toEqual(false); + expect(parseBoolean(new Uint8Array([0xff]))).toEqual(true); }); }); describe('parseBitString', () => { it('parses bit strings', () => { - expect(parseBitString(Buffer.from([0x04, 0x57, 0xd0]))).toEqual([ + expect(parseBitString(new Uint8Array([0x04, 0x57, 0xd0]))).toEqual([ 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, ]); // Since the last four bits are ignored, the parsed bit string is // identical to the example above. - expect(parseBitString(Buffer.from([0x04, 0x57, 0xdf]))).toEqual([ + expect(parseBitString(new Uint8Array([0x04, 0x57, 0xdf]))).toEqual([ 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, ]); }); diff --git a/packages/core/src/__tests__/crypto.test.ts b/packages/core/src/__tests__/crypto.test.ts index 9aba339a3..008015a85 100644 --- a/packages/core/src/__tests__/crypto.test.ts +++ b/packages/core/src/__tests__/crypto.test.ts @@ -14,6 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ import { bufferEqual, createPublicKey, hash } from '../crypto'; +import { base64ToUint8Array, stringToUint8Array, uint8ArrayToHex } from '../encoding'; describe('createPublicKey', () => { it('should create a public key from a PEM string', () => { @@ -28,9 +29,8 @@ rkBbmLSGtks4L3qX6yYY0zufBnhC8Ur/iy55GhWP/9A/bY2LhC30M9+RYtw== }); it('should create a public key from a DER buffer', () => { - const input = Buffer.from( - 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE2G2Y+2tabdTV5BcGiBIx0a9fAFwrkBbmLSGtks4L3qX6yYY0zufBnhC8Ur/iy55GhWP/9A/bY2LhC30M9+RYtw==', - 'base64' + const input = base64ToUint8Array( + 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE2G2Y+2tabdTV5BcGiBIx0a9fAFwrkBbmLSGtks4L3qX6yYY0zufBnhC8Ur/iy55GhWP/9A/bY2LhC30M9+RYtw==' ); const key = createPublicKey(input); expect(key).toBeDefined(); @@ -41,9 +41,9 @@ rkBbmLSGtks4L3qX6yYY0zufBnhC8Ur/iy55GhWP/9A/bY2LhC30M9+RYtw== describe('hash', () => { it('returns the SHA256 digest of the blob', () => { - const blob = Buffer.from('hello world'); + const blob = stringToUint8Array('hello world'); const digest = hash(blob); - expect(digest.toString('hex')).toBe( + expect(uint8ArrayToHex(digest)).toBe( 'b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9' ); }); @@ -51,14 +51,14 @@ describe('hash', () => { describe('bufferEqual', () => { it('returns true when the buffers are equal', () => { - const a = Buffer.from('hello world'); - const b = Buffer.from('hello world'); + const a = stringToUint8Array('hello world'); + const b = stringToUint8Array('hello world'); expect(bufferEqual(a, b)).toBe(true); }); it('returns false when the buffers are not equal', () => { - const a = Buffer.from('hello world'); - const b = Buffer.from('hello world!'); + const a = stringToUint8Array('hello world'); + const b = stringToUint8Array('hello world!'); expect(bufferEqual(a, b)).toBe(false); }); }); diff --git a/packages/core/src/__tests__/dsse.test.ts b/packages/core/src/__tests__/dsse.test.ts index 077010681..743b72d66 100644 --- a/packages/core/src/__tests__/dsse.test.ts +++ b/packages/core/src/__tests__/dsse.test.ts @@ -14,13 +14,14 @@ See the License for the specific language governing permissions and limitations under the License. */ import { preAuthEncoding } from '../dsse'; +import { stringToUint8Array } from '../encoding'; describe('preAuthEncoding', () => { const payloadType = 'text/plain'; - const payload = Buffer.from('Hello, World!', 'utf8'); + const payload = stringToUint8Array('Hello, World!', 'utf8'); it('should return the correct pre-auth encoding', () => { const pae = preAuthEncoding(payloadType, payload); - expect(pae).toEqual(Buffer.from('DSSEv1 10 text/plain 13 Hello, World!')); + expect(pae).toEqual(stringToUint8Array('DSSEv1 10 text/plain 13 Hello, World!')); }); }); diff --git a/packages/core/src/__tests__/pem.test.ts b/packages/core/src/__tests__/pem.test.ts index 45b780ce3..ec8faf106 100644 --- a/packages/core/src/__tests__/pem.test.ts +++ b/packages/core/src/__tests__/pem.test.ts @@ -14,6 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ import { fromDER, toDER } from '../pem'; +import { base64ToUint8Array } from '../encoding'; describe('toDER', () => { describe('when the object is a certificate', () => { @@ -21,7 +22,7 @@ describe('toDER', () => { '-----BEGIN CERTIFICATE-----\nABCD\n-----END CERTIFICATE-----\n'; it('returns a DER-encoded certificate', () => { const der = toDER(pem); - expect(der).toEqual(Buffer.from('ABCD', 'base64')); + expect(der).toEqual(base64ToUint8Array('ABCD')); }); }); @@ -29,7 +30,7 @@ describe('toDER', () => { const pem = '-----BEGIN PUBLIC KEY-----\nDEFG\n-----END PUBLIC KEY-----\n'; it('returns a DER-encoded key', () => { const der = toDER(pem); - expect(der).toEqual(Buffer.from('DEFG', 'base64')); + expect(der).toEqual(base64ToUint8Array('DEFG')); }); }); }); @@ -49,7 +50,7 @@ describe('fromDER', () => { describe('when an empty buffer is provided', () => { it('returns just the PEM headers', () => { - const pem = fromDER(Buffer.from('')); + const pem = fromDER(base64ToUint8Array('')); expect(pem).toEqual( '-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----\n' ); diff --git a/packages/core/src/__tests__/rfc3161/timestamp.test.ts b/packages/core/src/__tests__/rfc3161/timestamp.test.ts index 7980cadce..8a7b66963 100644 --- a/packages/core/src/__tests__/rfc3161/timestamp.test.ts +++ b/packages/core/src/__tests__/rfc3161/timestamp.test.ts @@ -16,9 +16,10 @@ limitations under the License. import { createPublicKey } from '../../crypto'; import { RFC3161TimestampVerificationError } from '../../rfc3161/error'; import { RFC3161Timestamp } from '../../rfc3161/timestamp'; +import { base64ToUint8Array, hexToUint8Array, stringToUint8Array } from '../../encoding'; describe('RFC3161Timestamp', () => { - const artifact = Buffer.from('hello, world\n'); + const artifact = stringToUint8Array('hello, world\n'); const publicKey = '-----BEGIN PUBLIC KEY-----\n' + @@ -27,9 +28,8 @@ describe('RFC3161Timestamp', () => { 'hqpsgFMh5b5J90HJLK7HOyUZjehAnvSn\n' + '-----END PUBLIC KEY-----\n'; - const ts = Buffer.from( - 'MIIC0TADAgEAMIICyAYJKoZIhvcNAQcCoIICuTCCArUCAQExDTALBglghkgBZQMEAgIwgbwGCyqGSIb3DQEJEAEEoIGsBIGpMIGmAgEBBgkrBgEEAYO/MAIwMTANBglghkgBZQMEAgEFAAQghT/5N2Kgbdv3IsTr6d3WbY9j3a6pf1IcPswg2nyXYCACFQCyi6gMhpheZVlBHi153EZai5EdTBgPMjAyMzEyMjAyMTQ5MThaMAMCAQGgNqQ0MDIxFTATBgNVBAoTDEdpdEh1YiwgSW5jLjEZMBcGA1UEAxMQVFNBIFRpbWVzdGFtcGluZ6AAMYIB3jCCAdoCAQEwSjAyMRUwEwYDVQQKEwxHaXRIdWIsIEluYy4xGTAXBgNVBAMTEFRTQSBpbnRlcm1lZGlhdGUCFDQ1ZZrWbr6Lo5+CsIgv6MSK/IcQMAsGCWCGSAFlAwQCAqCCAQUwGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEEMBwGCSqGSIb3DQEJBTEPFw0yMzEyMjAyMTQ5MThaMD8GCSqGSIb3DQEJBDEyBDDvZfw23I/Jvgh0uo9mfMqkEwBvpUfpkmJfUUImoY0Ist/AwWJZxk/yJvNZ464B7vowgYcGCyqGSIb3DQEJEAIvMXgwdjB0MHIEIC4X67ezV4q0OFecnkRUAx6sVRjb/Q6nZYy0cfMfHKgBME4wNqQ0MDIxFTATBgNVBAoTDEdpdEh1YiwgSW5jLjEZMBcGA1UEAxMQVFNBIGludGVybWVkaWF0ZQIUNDVlmtZuvoujn4KwiC/oxIr8hxAwCgYIKoZIzj0EAwMEZzBlAjEAjplaA2ukG3aI+Zf2nqbI8QqpWXTeJGt7OUT23bYDx84OPK/BBn9NR8JkeO41EtN7AjAozvkg9Wi8deG8pZt3Pj/ip+cvL4X3IktD63SS/+rh+/BrYMWawKT6yu8T3MMsQ+E=', - 'base64' + const ts = base64ToUint8Array( + 'MIIC0TADAgEAMIICyAYJKoZIhvcNAQcCoIICuTCCArUCAQExDTALBglghkgBZQMEAgIwgbwGCyqGSIb3DQEJEAEEoIGsBIGpMIGmAgEBBgkrBgEEAYO/MAIwMTANBglghkgBZQMEAgEFAAQghT/5N2Kgbdv3IsTr6d3WbY9j3a6pf1IcPswg2nyXYCACFQCyi6gMhpheZVlBHi153EZai5EdTBgPMjAyMzEyMjAyMTQ5MThaMAMCAQGgNqQ0MDIxFTATBgNVBAoTDEdpdEh1YiwgSW5jLjEZMBcGA1UEAxMQVFNBIFRpbWVzdGFtcGluZ6AAMYIB3jCCAdoCAQEwSjAyMRUwEwYDVQQKEwxHaXRIdWIsIEluYy4xGTAXBgNVBAMTEFRTQSBpbnRlcm1lZGlhdGUCFDQ1ZZrWbr6Lo5+CsIgv6MSK/IcQMAsGCWCGSAFlAwQCAqCCAQUwGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEEMBwGCSqGSIb3DQEJBTEPFw0yMzEyMjAyMTQ5MThaMD8GCSqGSIb3DQEJBDEyBDDvZfw23I/Jvgh0uo9mfMqkEwBvpUfpkmJfUUImoY0Ist/AwWJZxk/yJvNZ464B7vowgYcGCyqGSIb3DQEJEAIvMXgwdjB0MHIEIC4X67ezV4q0OFecnkRUAx6sVRjb/Q6nZYy0cfMfHKgBME4wNqQ0MDIxFTATBgNVBAoTDEdpdEh1YiwgSW5jLjEZMBcGA1UEAxMQVFNBIGludGVybWVkaWF0ZQIUNDVlmtZuvoujn4KwiC/oxIr8hxAwCgYIKoZIzj0EAwMEZzBlAjEAjplaA2ukG3aI+Zf2nqbI8QqpWXTeJGt7OUT23bYDx84OPK/BBn9NR8JkeO41EtN7AjAozvkg9Wi8deG8pZt3Pj/ip+cvL4X3IktD63SS/+rh+/BrYMWawKT6yu8T3MMsQ+E=' ); const subject = RFC3161Timestamp.parse(ts); @@ -55,7 +55,7 @@ describe('RFC3161Timestamp', () => { describe('signerSerialNumber', () => { it('should return the serial number of the signing certificate', () => { expect(subject.signerSerialNumber).toEqual( - Buffer.from('3435659AD66EBE8BA39F82B0882FE8C48AFC8710', 'hex') + hexToUint8Array('3435659AD66EBE8BA39F82B0882FE8C48AFC8710') ); }); }); @@ -86,7 +86,7 @@ describe('RFC3161Timestamp', () => { describe('when the artifact does NOT match the one which was signed', () => { const subject = RFC3161Timestamp.parse(ts); const key = createPublicKey(publicKey); - const data = Buffer.from('oops'); + const data = stringToUint8Array('oops'); it('throws an error', () => { expect(() => subject.verify(data, key)).toThrow( @@ -115,9 +115,8 @@ describe('RFC3161Timestamp', () => { describe('when the content type is NOT signedData', () => { const data = artifact; const subject = RFC3161Timestamp.parse( - Buffer.from( - 'MIICHDADAgEAMIICEwYJKoZIhvcNAQcDoIICBDCCAgACAQMxDzANBglghkgBZQMEAgEFADB0BgsqhkiG9w0BCRABBKBlBGMwYQIBAQYJKwYBBAGDvzACMC8wCwYJYIZIAWUDBAIBBCCFP/k3YqBt2/cixOvp3dZtj2Pdrql/Uhw+zCDafJdgIAIE3q2+7xgPMjAzMDAxMDEwMDAwMDBaMAMCAQECBEmWAtKgADGCAXAwggFsAgEBMCswJjEMMAoGA1UEAxMDdHNhMRYwFAYDVQQKEw1zaWdzdG9yZS5tb2NrAgECMA0GCWCGSAFlAwQCAQUAoIHVMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcNMzAwMTAxMDAwMDAwWjAvBgkqhkiG9w0BCQQxIgQg9EVaiVg5rwrcg1wj/j99tIJrWKYn60AIthUWerryKLcwaAYLKoZIhvcNAQkQAi8xWTBXMFUwUwQgvgCzJyhCRVJAO8TE9bSZaZbQEA7BBdhR2jom19ZI/icwLzAqpCgwJjEMMAoGA1UEAxMDdHNhMRYwFAYDVQQKEw1zaWdzdG9yZS5tb2NrAgECMAoGCCqGSM49BAMCBEcwRQIhAN7VR7nM4ppVskxDo5PiWGiIaPB6Cf76vRohGAmU5uo7AiAWlZC7auQlm8xTwpBkgJDd0dXsTesTfeMoREFKXdDzMw==', - 'base64' + base64ToUint8Array( + 'MIICHDADAgEAMIICEwYJKoZIhvcNAQcDoIICBDCCAgACAQMxDzANBglghkgBZQMEAgEFADB0BgsqhkiG9w0BCRABBKBlBGMwYQIBAQYJKwYBBAGDvzACMC8wCwYJYIZIAWUDBAIBBCCFP/k3YqBt2/cixOvp3dZtj2Pdrql/Uhw+zCDafJdgIAIE3q2+7xgPMjAzMDAxMDEwMDAwMDBaMAMCAQECBEmWAtKgADGCAXAwggFsAgEBMCswJjEMMAoGA1UEAxMDdHNhMRYwFAYDVQQKEw1zaWdzdG9yZS5tb2NrAgECMA0GCWCGSAFlAwQCAQUAoIHVMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcNMzAwMTAxMDAwMDAwWjAvBgkqhkiG9w0BCQQxIgQg9EVaiVg5rwrcg1wj/j99tIJrWKYn60AIthUWerryKLcwaAYLKoZIhvcNAQkQAi8xWTBXMFUwUwQgvgCzJyhCRVJAO8TE9bSZaZbQEA7BBdhR2jom19ZI/icwLzAqpCgwJjEMMAoGA1UEAxMDdHNhMRYwFAYDVQQKEw1zaWdzdG9yZS5tb2NrAgECMAoGCCqGSM49BAMCBEcwRQIhAN7VR7nM4ppVskxDo5PiWGiIaPB6Cf76vRohGAmU5uo7AiAWlZC7auQlm8xTwpBkgJDd0dXsTesTfeMoREFKXdDzMw==' ) ); const key = createPublicKey( @@ -137,9 +136,8 @@ describe('RFC3161Timestamp', () => { describe('when the encapsulated content type is NOT tstInfo', () => { const data = artifact; const subject = RFC3161Timestamp.parse( - Buffer.from( - 'MIICITADAgEAMIICGAYJKoZIhvcNAQcCoIICCTCCAgUCAQMxDzANBglghkgBZQMEAgEFADB4BgsqhkiG9w0BCRABBaBpBGcwZQIBAQYJKwYBBAGDvzACMC8wCwYJYIZIAWUDBAIBBCCFP/k3YqBt2/cixOvp3dZtj2Pdrql/Uhw+zCDafJdgIAIE3q2+7xgTMjAyMzEyMjExOTEwNTguNDI2WjADAgEBAgRJlgLSoAAxggFxMIIBbQIBATArMCYxDDAKBgNVBAMTA3RzYTEWMBQGA1UEChMNc2lnc3RvcmUubW9jawIBAjANBglghkgBZQMEAgEFAKCB1TAaBgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQUwHAYJKoZIhvcNAQkFMQ8XDTIzMTIyMTE5MTA1OFowLwYJKoZIhvcNAQkEMSIEILhMPeMNPj1iPtE7ztAzXNMco3qGrxS5LwFORL66zN6PMGgGCyqGSIb3DQEJEAIvMVkwVzBVMFMEIIdLV5cij9fs6Nm62roSAclDR2JC116C4Hp61tEMWTsZMC8wKqQoMCYxDDAKBgNVBAMTA3RzYTEWMBQGA1UEChMNc2lnc3RvcmUubW9jawIBAjAKBggqhkjOPQQDAgRIMEYCIQDQN2PgaZ38no/tP/NpncFPskEh1tVGqj4n+pe4VeGYPgIhAKtXSYiKZARsIHepbROedQvFnq0JP3mZaQ+r1kYI5Tuk', - 'base64' + base64ToUint8Array( + 'MIICITADAgEAMIICGAYJKoZIhvcNAQcCoIICCTCCAgUCAQMxDzANBglghkgBZQMEAgEFADB4BgsqhkiG9w0BCRABBaBpBGcwZQIBAQYJKwYBBAGDvzACMC8wCwYJYIZIAWUDBAIBBCCFP/k3YqBt2/cixOvp3dZtj2Pdrql/Uhw+zCDafJdgIAIE3q2+7xgTMjAyMzEyMjExOTEwNTguNDI2WjADAgEBAgRJlgLSoAAxggFxMIIBbQIBATArMCYxDDAKBgNVBAMTA3RzYTEWMBQGA1UEChMNc2lnc3RvcmUubW9jawIBAjANBglghkgBZQMEAgEFAKCB1TAaBgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQUwHAYJKoZIhvcNAQkFMQ8XDTIzMTIyMTE5MTA1OFowLwYJKoZIhvcNAQkEMSIEILhMPeMNPj1iPtE7ztAzXNMco3qGrxS5LwFORL66zN6PMGgGCyqGSIb3DQEJEAIvMVkwVzBVMFMEIIdLV5cij9fs6Nm62roSAclDR2JC116C4Hp61tEMWTsZMC8wKqQoMCYxDDAKBgNVBAMTA3RzYTEWMBQGA1UEChMNc2lnc3RvcmUubW9jawIBAjAKBggqhkjOPQQDAgRIMEYCIQDQN2PgaZ38no/tP/NpncFPskEh1tVGqj4n+pe4VeGYPgIhAKtXSYiKZARsIHepbROedQvFnq0JP3mZaQ+r1kYI5Tuk' ) ); const key = createPublicKey( @@ -160,7 +158,7 @@ describe('RFC3161Timestamp', () => { const data = artifact; const key = createPublicKey(publicKey); const subject = RFC3161Timestamp.parse( - Buffer.from('30053003020100', 'hex') + hexToUint8Array('30053003020100') ); it('throws an error', () => { expect(() => subject.verify(data, key)).toThrow( @@ -172,9 +170,8 @@ describe('RFC3161Timestamp', () => { describe('when the signed message does NOT match the tstInfo', () => { const data = artifact; const subject = RFC3161Timestamp.parse( - Buffer.from( - 'MIICHzADAgEAMIICFgYJKoZIhvcNAQcCoIICBzCCAgMCAQMxDzANBglghkgBZQMEAgEFADB4BgsqhkiG9w0BCRABBKBpBGcwZQIBAQYJKwYBBAGDvzACMC8wCwYJYIZIAWUDBAIBBCCFP/k3YqBt2/cixOvp3dZtj2Pdrql/Uhw+zCDafJdgIAIE3q2+7xgTMjAyMzEyMjExOTE2MzIuNzE4WjADAgEBAgRJlgLSoAAxggFvMIIBawIBATArMCYxDDAKBgNVBAMTA3RzYTEWMBQGA1UEChMNc2lnc3RvcmUubW9jawIBAjANBglghkgBZQMEAgEFAKCB1TAaBgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwHAYJKoZIhvcNAQkFMQ8XDTIzMTIyMTE5MTYzMlowLwYJKoZIhvcNAQkEMSIEIJuptzDaKrDb239c8R2sNeHm6xCkRN81uAsObeDpWZHJMGgGCyqGSIb3DQEJEAIvMVkwVzBVMFMEILXG2YeUshi7GamxglcNv0Udq53SwfXSM6LhJbmA82OQMC8wKqQoMCYxDDAKBgNVBAMTA3RzYTEWMBQGA1UEChMNc2lnc3RvcmUubW9jawIBAjAKBggqhkjOPQQDAgRGMEQCIARr+DJVotgq2uQAEoTzkSg2Fo/LHarefdlxvUUvvxZfAiAzCJhmXfchOfsl6wlPfV9zCZsJXIMG4yY7sCQOS/wiHQ==', - 'base64' + base64ToUint8Array( + 'MIICHzADAgEAMIICFgYJKoZIhvcNAQcCoIICBzCCAgMCAQMxDzANBglghkgBZQMEAgEFADB4BgsqhkiG9w0BCRABBKBpBGcwZQIBAQYJKwYBBAGDvzACMC8wCwYJYIZIAWUDBAIBBCCFP/k3YqBt2/cixOvp3dZtj2Pdrql/Uhw+zCDafJdgIAIE3q2+7xgTMjAyMzEyMjExOTE2MzIuNzE4WjADAgEBAgRJlgLSoAAxggFvMIIBawIBATArMCYxDDAKBgNVBAMTA3RzYTEWMBQGA1UEChMNc2lnc3RvcmUubW9jawIBAjANBglghkgBZQMEAgEFAKCB1TAaBgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwHAYJKoZIhvcNAQkFMQ8XDTIzMTIyMTE5MTYzMlowLwYJKoZIhvcNAQkEMSIEIJuptzDaKrDb239c8R2sNeHm6xCkRN81uAsObeDpWZHJMGgGCyqGSIb3DQEJEAIvMVkwVzBVMFMEILXG2YeUshi7GamxglcNv0Udq53SwfXSM6LhJbmA82OQMC8wKqQoMCYxDDAKBgNVBAMTA3RzYTEWMBQGA1UEChMNc2lnc3RvcmUubW9jawIBAjAKBggqhkjOPQQDAgRGMEQCIARr+DJVotgq2uQAEoTzkSg2Fo/LHarefdlxvUUvvxZfAiAzCJhmXfchOfsl6wlPfV9zCZsJXIMG4yY7sCQOS/wiHQ==' ) ); const key = createPublicKey( diff --git a/packages/core/src/__tests__/rfc3161/tstinfo.test.ts b/packages/core/src/__tests__/rfc3161/tstinfo.test.ts index 1f64573e3..ffab3b91c 100644 --- a/packages/core/src/__tests__/rfc3161/tstinfo.test.ts +++ b/packages/core/src/__tests__/rfc3161/tstinfo.test.ts @@ -16,11 +16,11 @@ limitations under the License. import { ASN1Obj } from '../../asn1'; import { RFC3161TimestampVerificationError } from '../../rfc3161/error'; import { TSTInfo } from '../../rfc3161/tstinfo'; +import { hexToUint8Array, stringToUint8Array } from '../../encoding'; describe('TSTInfo', () => { - const tstInfoDER = Buffer.from( - '3081a602010106092b0601040183bf30023031300d060960864801650304020105000420853ff93762a06ddbf722c4ebe9ddd66d8f63ddaea97f521c3ecc20da7c976020021500b28ba80c86985e6559411e2d79dc465a8b911d4c180f32303233313232303231343931385a3003020101a036a434303231153013060355040a130c4769744875622c20496e632e31193017060355040313105453412054696d657374616d70696e67', - 'hex' + const tstInfoDER = hexToUint8Array( + '3081a602010106092b0601040183bf30023031300d060960864801650304020105000420853ff93762a06ddbf722c4ebe9ddd66d8f63ddaea97f521c3ecc20da7c976020021500b28ba80c86985e6559411e2d79dc465a8b911d4c180f32303233313232303231343931385a3003020101a036a434303231153013060355040a130c4769744875622c20496e632e31193017060355040313105453412054696d657374616d70696e67' ); const asn1 = ASN1Obj.parseBuffer(tstInfoDER); const subject = new TSTInfo(asn1); @@ -51,7 +51,7 @@ describe('TSTInfo', () => { describe('verify', () => { describe('when the messageImprintHashedMessage matches the artifact', () => { - const artifact = Buffer.from('hello, world\n'); + const artifact = stringToUint8Array('hello, world\n'); it('does not throw an error', () => { expect(() => subject.verify(artifact)).not.toThrow(); @@ -59,7 +59,7 @@ describe('TSTInfo', () => { }); describe('when the messageImprintHashedMessage does NOT match the artifact', () => { - const artifact = Buffer.from('oops'); + const artifact = stringToUint8Array('oops'); it('throws an error', () => { expect(() => subject.verify(artifact)).toThrow( diff --git a/packages/core/src/__tests__/stream.test.ts b/packages/core/src/__tests__/stream.test.ts index 7ea1c931c..21cbf1d34 100644 --- a/packages/core/src/__tests__/stream.test.ts +++ b/packages/core/src/__tests__/stream.test.ts @@ -16,7 +16,7 @@ limitations under the License. import { ByteStream } from '../stream'; describe('ByteStream', () => { - const buf = Buffer.from([ + const buf = new Uint8Array([ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, ]); const subject = new ByteStream(buf); @@ -120,7 +120,7 @@ describe('ByteStream', () => { it('appends a character to the buffer', () => { subject.appendChar(0x0a); - expect(subject.buffer).toEqual(Buffer.from([0x0a])); + expect(subject.buffer).toEqual(new Uint8Array([0x0a])); expect(subject.position).toEqual(1); }); }); @@ -130,7 +130,7 @@ describe('ByteStream', () => { it('appends a uint16 to the buffer', () => { subject.appendUint16(0x0a0b); - expect(subject.buffer).toEqual(Buffer.from([0x0a, 0x0b])); + expect(subject.buffer).toEqual(new Uint8Array([0x0a, 0x0b])); expect(subject.position).toEqual(2); }); }); @@ -140,7 +140,7 @@ describe('ByteStream', () => { it('appends a uint24 to the buffer', () => { subject.appendUint24(0x0a0b0c); - expect(subject.buffer).toEqual(Buffer.from([0x0a, 0x0b, 0x0c])); + expect(subject.buffer).toEqual(new Uint8Array([0x0a, 0x0b, 0x0c])); expect(subject.position).toEqual(3); }); }); @@ -158,7 +158,7 @@ describe('ByteStream', () => { const viewSize = 9999; it('allocates the necessary space and appends the view to the buffer', () => { - subject.appendView(Buffer.alloc(viewSize)); + subject.appendView(new Uint8Array(viewSize)); expect(subject.position).toEqual(buf.length + viewSize); }); }); diff --git a/packages/core/src/__tests__/x509/cert.test.ts b/packages/core/src/__tests__/x509/cert.test.ts index 5c686adfa..9c69e7dbf 100644 --- a/packages/core/src/__tests__/x509/cert.test.ts +++ b/packages/core/src/__tests__/x509/cert.test.ts @@ -15,6 +15,7 @@ limitations under the License. */ import { X509Certificate } from '../../x509/cert'; import { certificates } from '../__fixtures__/certs'; +import { base64ToUint8Array, hexToUint8Array } from '../../encoding'; describe('X509Certificate', () => { describe('.parse', () => { @@ -24,7 +25,7 @@ describe('X509Certificate', () => { expect(cert.version).toBe('v3'); expect(cert.serialNumber).toEqual( - Buffer.from('61CC29EC72F2E28458A0C330B7E8D40357FAFE9E', 'hex') + hexToUint8Array('61CC29EC72F2E28458A0C330B7E8D40357FAFE9E') ); expect(cert.notBefore).toBeInstanceOf(Date); expect(cert.notBefore.toISOString()).toBe('1990-01-01T00:00:00.000Z'); diff --git a/packages/core/src/__tests__/x509/ext.test.ts b/packages/core/src/__tests__/x509/ext.test.ts index 056d526ac..df4eca2f6 100644 --- a/packages/core/src/__tests__/x509/ext.test.ts +++ b/packages/core/src/__tests__/x509/ext.test.ts @@ -24,10 +24,11 @@ import { X509SubjectKeyIDExtension, } from '../../x509/ext'; import { SignedCertificateTimestamp } from '../../x509/sct'; +import { hexToUint8Array, uint8ArrayToHex } from '../../encoding'; describe('x509Extension', () => { describe('constructor', () => { - const extension = Buffer.from('300F0603551D130101FF040530030101FF', 'hex'); + const extension = hexToUint8Array('300F0603551D130101FF040530030101FF'); const obj = ASN1Obj.parseBuffer(extension); it('parses the extension', () => { @@ -38,16 +39,16 @@ describe('x509Extension', () => { }); describe('#value', () => { - const extension = Buffer.from('300F0603551D130101FF040530030101FF', 'hex'); + const extension = hexToUint8Array('300F0603551D130101FF040530030101FF'); const subject = new X509Extension(ASN1Obj.parseBuffer(extension)); it('returns the value', () => { - expect(subject.value.toString('hex')).toBe('30030101ff'); + expect(uint8ArrayToHex(subject.value)).toBe('30030101ff'); }); }); describe('#valueObj', () => { - const extension = Buffer.from('300F0603551D130101FF040530030101FF', 'hex'); + const extension = hexToUint8Array('300F0603551D130101FF040530030101FF'); const subject = new X509Extension(ASN1Obj.parseBuffer(extension)); it('returns the value', () => { @@ -60,9 +61,8 @@ describe('x509Extension', () => { describe('x509BasicConstraintsExtension', () => { describe('constructor', () => { - const basicConstraintsExtension = Buffer.from( - '300F0603551D130101FF040530030101FF', - 'hex' + const basicConstraintsExtension = hexToUint8Array( + '300F0603551D130101FF040530030101FF' ); const obj = ASN1Obj.parseBuffer(basicConstraintsExtension); @@ -76,9 +76,8 @@ describe('x509BasicConstraintsExtension', () => { describe('#isCA', () => { describe('when the extension is not a CA', () => { // Extension w/ isCA = false - const basicConstraintsExtension = Buffer.from( - '300F0603551D130101FF04053003010100', - 'hex' + const basicConstraintsExtension = hexToUint8Array( + '300F0603551D130101FF04053003010100' ); const subject = new X509BasicConstraintsExtension( ASN1Obj.parseBuffer(basicConstraintsExtension) @@ -91,9 +90,8 @@ describe('x509BasicConstraintsExtension', () => { describe('when the extension is a CA', () => { // Extension w/ isCA = true - const basicConstraintsExtension = Buffer.from( - '300F0603551D130101FF040530030101FF', - 'hex' + const basicConstraintsExtension = hexToUint8Array( + '300F0603551D130101FF040530030101FF' ); const subject = new X509BasicConstraintsExtension( ASN1Obj.parseBuffer(basicConstraintsExtension) @@ -106,9 +104,9 @@ describe('x509BasicConstraintsExtension', () => { describe('when the extension contains no value for the CA', () => { // Extension w/ NO isCA value specified - const basicConstraintsExtension = Buffer.from( - '300C0603551D130101FF04023000', - 'hex' + const basicConstraintsExtension = hexToUint8Array( + '300C0603551D130101FF04023000' + ); const subject = new X509BasicConstraintsExtension( ASN1Obj.parseBuffer(basicConstraintsExtension) @@ -123,9 +121,8 @@ describe('x509BasicConstraintsExtension', () => { describe('#pathLenConstraint', () => { describe('when the extension has no pathLenConstraint', () => { // Extension w/ isCA = true, no pathLenConstraint - const basicConstraintsExtension = Buffer.from( - '300F0603551D130101FF040530030101FF', - 'hex' + const basicConstraintsExtension = hexToUint8Array( + '300F0603551D130101FF040530030101FF' ); const subject = new X509BasicConstraintsExtension( ASN1Obj.parseBuffer(basicConstraintsExtension) @@ -138,9 +135,8 @@ describe('x509BasicConstraintsExtension', () => { describe('when the extension has a pathLenConstraint', () => { // Extension w/ isCA = true, no pathLenConstraint - const basicConstraintsExtension = Buffer.from( - '30120603551D130101FF040830060101FF020101', - 'hex' + const basicConstraintsExtension = hexToUint8Array( + '30120603551D130101FF040830060101FF020101' ); const subject = new X509BasicConstraintsExtension( ASN1Obj.parseBuffer(basicConstraintsExtension) @@ -155,9 +151,8 @@ describe('x509BasicConstraintsExtension', () => { describe('x509KeyUsageExtension', () => { describe('constructor', () => { - const keyUsageExtension = Buffer.from( - '300E0603551D0F0101FF040403020780', - 'hex' + const keyUsageExtension = hexToUint8Array( + '300E0603551D0F0101FF040403020780' ); const obj = ASN1Obj.parseBuffer(keyUsageExtension); @@ -171,9 +166,8 @@ describe('x509KeyUsageExtension', () => { describe('#digitalSignature', () => { describe('when the extension has the digitalSignature bit set', () => { // Extension w/ digitalSignature bit set - const keyUsageExtension = Buffer.from( - '300E0603551D0F0101FF040403020780', - 'hex' + const keyUsageExtension = hexToUint8Array( + '300E0603551D0F0101FF040403020780' ); const subject = new X509KeyUsageExtension( ASN1Obj.parseBuffer(keyUsageExtension) @@ -186,9 +180,8 @@ describe('x509KeyUsageExtension', () => { describe('when the extension does not have the digitalSignature bit set', () => { // Extension w/ digitalSignature bit unset - const keyUsageExtension = Buffer.from( - '300E0603551D0F0101FF040403020700', - 'hex' + const keyUsageExtension = hexToUint8Array( + '300E0603551D0F0101FF040403020700' ); const subject = new X509KeyUsageExtension( ASN1Obj.parseBuffer(keyUsageExtension) @@ -203,9 +196,8 @@ describe('x509KeyUsageExtension', () => { describe('#keyCertSign', () => { describe('when the extension has the keyCertSign bit set', () => { // Extension w/ keyCertSign bit set - const keyUsageExtension = Buffer.from( - '300E0603551D0F0101FF040403020204', - 'hex' + const keyUsageExtension = hexToUint8Array( + '300E0603551D0F0101FF040403020204' ); const subject = new X509KeyUsageExtension( ASN1Obj.parseBuffer(keyUsageExtension) @@ -218,9 +210,8 @@ describe('x509KeyUsageExtension', () => { describe('when the extension does not have the keyCertSign bit set', () => { // Extension w/ keyCertSign bit unset - const keyUsageExtension = Buffer.from( - '300E0603551D0F0101FF040403020200', - 'hex' + const keyUsageExtension = hexToUint8Array( + '300E0603551D0F0101FF040403020200' ); const subject = new X509KeyUsageExtension( ASN1Obj.parseBuffer(keyUsageExtension) @@ -235,9 +226,8 @@ describe('x509KeyUsageExtension', () => { describe('#crlSign', () => { describe('when the extension has the cRLSign bit set', () => { // Extension w/ cRLSign bit set - const keyUsageExtension = Buffer.from( - '300E0603551D0F0101FF040403020102', - 'hex' + const keyUsageExtension = hexToUint8Array( + '300E0603551D0F0101FF040403020102' ); const subject = new X509KeyUsageExtension( ASN1Obj.parseBuffer(keyUsageExtension) @@ -250,9 +240,8 @@ describe('x509KeyUsageExtension', () => { describe('when the extension does not have the cRLSign bit set', () => { // Extension w/ cRLSign bit unset - const keyUsageExtension = Buffer.from( - '300E0603551D0F0101FF040403020100', - 'hex' + const keyUsageExtension = hexToUint8Array( + '300E0603551D0F0101FF040403020100' ); const subject = new X509KeyUsageExtension( ASN1Obj.parseBuffer(keyUsageExtension) @@ -267,9 +256,8 @@ describe('x509KeyUsageExtension', () => { describe('x509SubjectAlternativeNameExtension', () => { describe('constructor', () => { - const subjectAltNameExtension = Buffer.from( - '301F0603551D110101FF041530138111627269616E40646568616D65722E636F6D', - 'hex' + const subjectAltNameExtension = hexToUint8Array( + '301F0603551D110101FF041530138111627269616E40646568616D65722E636F6D' ); const obj = ASN1Obj.parseBuffer(subjectAltNameExtension); @@ -283,9 +271,8 @@ describe('x509SubjectAlternativeNameExtension', () => { describe('#rfc822Name', () => { describe('when the extension has an rfc822Name', () => { // Extension w/ rfc822Name - const subjectAltNameExtension = Buffer.from( - '30190603551D110101FF040F300D810B666F6F406261722E636F6D', - 'hex' + const subjectAltNameExtension = hexToUint8Array( + '30190603551D110101FF040F300D810B666F6F406261722E636F6D' ); const subject = new X509SubjectAlternativeNameExtension( ASN1Obj.parseBuffer(subjectAltNameExtension) @@ -298,9 +285,8 @@ describe('x509SubjectAlternativeNameExtension', () => { describe('when the extension has a uri', () => { // Extension w/ uri - const subjectAltNameExtension = Buffer.from( - '30190603551D110101FF040F300D860B666F6F406261722E636F6D', - 'hex' + const subjectAltNameExtension = hexToUint8Array( + '30190603551D110101FF040F300D860B666F6F406261722E636F6D' ); const subject = new X509SubjectAlternativeNameExtension( ASN1Obj.parseBuffer(subjectAltNameExtension) @@ -315,9 +301,8 @@ describe('x509SubjectAlternativeNameExtension', () => { describe('#uri', () => { describe('when the extension has a uri', () => { // Extension w/ uri - const subjectAltNameExtension = Buffer.from( - '30190603551D110101FF040F300D860B666F6F406261722E636F6D', - 'hex' + const subjectAltNameExtension = hexToUint8Array( + '30190603551D110101FF040F300D860B666F6F406261722E636F6D' ); const subject = new X509SubjectAlternativeNameExtension( ASN1Obj.parseBuffer(subjectAltNameExtension) @@ -330,9 +315,8 @@ describe('x509SubjectAlternativeNameExtension', () => { describe('when the extension has an rfc822Name', () => { // Extension w/ rfc822Name - const subjectAltNameExtension = Buffer.from( - '30190603551D110101FF040F300D810B666F6F406261722E636F6D', - 'hex' + const subjectAltNameExtension = hexToUint8Array( + '30190603551D110101FF040F300D810B666F6F406261722E636F6D' ); const subject = new X509SubjectAlternativeNameExtension( ASN1Obj.parseBuffer(subjectAltNameExtension) @@ -347,9 +331,8 @@ describe('x509SubjectAlternativeNameExtension', () => { describe('#otherName', () => { describe('when the extension has an otherName', () => { // Extension w/ othername - const subjectAltNameExtension = Buffer.from( - '30260603551D11041F301DA01B060A2B0601040183BF300107A00D0C0B666F6F406261722E636F6D', - 'hex' + const subjectAltNameExtension = hexToUint8Array( + '30260603551D11041F301DA01B060A2B0601040183BF300107A00D0C0B666F6F406261722E636F6D' ); const subject = new X509SubjectAlternativeNameExtension( ASN1Obj.parseBuffer(subjectAltNameExtension) @@ -362,9 +345,8 @@ describe('x509SubjectAlternativeNameExtension', () => { describe('when the incorrect otherName OID is specified', () => { // Extension w/ othername - const subjectAltNameExtension = Buffer.from( - '30260603551D11041F301DA01B060A2B0601040183BF300107A00D0C0B666F6F406261722E636F6D', - 'hex' + const subjectAltNameExtension = hexToUint8Array( + '30260603551D11041F301DA01B060A2B0601040183BF300107A00D0C0B666F6F406261722E636F6D' ); const subject = new X509SubjectAlternativeNameExtension( ASN1Obj.parseBuffer(subjectAltNameExtension) @@ -377,9 +359,8 @@ describe('x509SubjectAlternativeNameExtension', () => { describe('when the extension has an rfc822Name', () => { // Extension w/ rfc822Name - const subjectAltNameExtension = Buffer.from( - '30190603551D110101FF040F300D810B666F6F406261722E636F6D', - 'hex' + const subjectAltNameExtension = hexToUint8Array( + '30190603551D110101FF040F300D810B666F6F406261722E636F6D' ); const subject = new X509SubjectAlternativeNameExtension( ASN1Obj.parseBuffer(subjectAltNameExtension) @@ -394,9 +375,8 @@ describe('x509SubjectAlternativeNameExtension', () => { describe('x509AuthorityKeyIDExtension', () => { describe('constructor', () => { - const akiExtension = Buffer.from( - '301F0603551D23041830168014875197D46B0D39CC9C44DFEDD1FBF77BF04F9B4F', - 'hex' + const akiExtension = hexToUint8Array( + '301F0603551D23041830168014875197D46B0D39CC9C44DFEDD1FBF77BF04F9B4F' ); const obj = ASN1Obj.parseBuffer(akiExtension); @@ -410,9 +390,8 @@ describe('x509AuthorityKeyIDExtension', () => { describe('#keyIdentifier', () => { describe('when the extension has a keyIdentifier', () => { // Extension w/ keyIdentifier - const akiExtension = Buffer.from( - '301F0603551D23041830168014875197D46B0D39CC9C44DFEDD1FBF77BF04F9B4F', - 'hex' + const akiExtension = hexToUint8Array( + '301F0603551D23041830168014875197D46B0D39CC9C44DFEDD1FBF77BF04F9B4F' ); const subject = new X509AuthorityKeyIDExtension( ASN1Obj.parseBuffer(akiExtension) @@ -420,16 +399,15 @@ describe('x509AuthorityKeyIDExtension', () => { it('returns the keyIdentifier', () => { expect(subject.keyIdentifier).toEqual( - Buffer.from('875197D46B0D39CC9C44DFEDD1FBF77BF04F9B4F', 'hex') + hexToUint8Array('875197D46B0D39CC9C44DFEDD1FBF77BF04F9B4F') ); }); }); describe('when the extension has NO keyIdentifier', () => { // Extension w/o keyIdentifier (bad context-specific tag) - const akiExtension = Buffer.from( - '301F0603551D23041830168114875197D46B0D39CC9C44DFEDD1FBF77BF04F9B4F', - 'hex' + const akiExtension = hexToUint8Array( + '301F0603551D23041830168114875197D46B0D39CC9C44DFEDD1FBF77BF04F9B4F' ); const subject = new X509AuthorityKeyIDExtension( ASN1Obj.parseBuffer(akiExtension) @@ -444,9 +422,8 @@ describe('x509AuthorityKeyIDExtension', () => { describe('x509SubjectKeyIDExtension', () => { describe('constructor', () => { - const skiExtension = Buffer.from( - '301D0603551D0E04160414BC8EE9246141781B89DB3CAB61A94F825A34C5A8', - 'hex' + const skiExtension = hexToUint8Array( + '301D0603551D0E04160414BC8EE9246141781B89DB3CAB61A94F825A34C5A8' ); const obj = ASN1Obj.parseBuffer(skiExtension); @@ -458,9 +435,8 @@ describe('x509SubjectKeyIDExtension', () => { }); describe('#keyIdentifier', () => { - const skiExtension = Buffer.from( - '301D0603551D0E04160414BC8EE9246141781B89DB3CAB61A94F825A34C5A8', - 'hex' + const skiExtension = hexToUint8Array( + '301D0603551D0E04160414BC8EE9246141781B89DB3CAB61A94F825A34C5A8' ); const subject = new X509SubjectKeyIDExtension( @@ -469,7 +445,7 @@ describe('x509SubjectKeyIDExtension', () => { it('returns the keyIdentifier', () => { expect(subject.keyIdentifier).toEqual( - Buffer.from('BC8EE9246141781B89DB3CAB61A94F825A34C5A8', 'hex') + hexToUint8Array('BC8EE9246141781B89DB3CAB61A94F825A34C5A8') ); }); }); @@ -477,9 +453,8 @@ describe('x509SubjectKeyIDExtension', () => { describe('x509SCTExtension', () => { describe('constructor', () => { - const sctExtension = Buffer.from( - '3012060A2B06010401D679020402040404020000', - 'hex' + const sctExtension = hexToUint8Array( + '3012060A2B06010401D679020402040404020000' ); const obj = ASN1Obj.parseBuffer(sctExtension); @@ -493,9 +468,8 @@ describe('x509SCTExtension', () => { describe('#signedCertificateTimestamps', () => { describe('when there are no SCTs in the extension', () => { // Extension w/ zero-length array of SCTs - const sctExtension = Buffer.from( - '3012060A2B06010401D679020402040404020000', - 'hex' + const sctExtension = hexToUint8Array( + '3012060A2B06010401D679020402040404020000' ); const subject = new X509SCTExtension(ASN1Obj.parseBuffer(sctExtension)); @@ -507,9 +481,8 @@ describe('x509SCTExtension', () => { }); describe('when there are SCTs in the extension', () => { - const sctExtension = Buffer.from( - '3043060A2B06010401D679020402043504330031002F0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', - 'hex' + const sctExtension = hexToUint8Array( + '3043060A2B06010401D679020402043504330031002F0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' ); const subject = new X509SCTExtension(ASN1Obj.parseBuffer(sctExtension)); @@ -523,10 +496,9 @@ describe('x509SCTExtension', () => { describe('when the stated length of the SCT list does not match the data ', () => { // Extension where length of SCT list is mismatched with the length of the constituent SCTs - const sctExtension = Buffer.from( + const sctExtension = hexToUint8Array( // |--| Should be 0x0031 for a valid SCT extension - '3043060A2B06010401D67902040204350433002F002F0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', - 'hex' + '3043060A2B06010401D67902040204350433002F002F0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' ); const subject = new X509SCTExtension(ASN1Obj.parseBuffer(sctExtension)); diff --git a/packages/core/src/__tests__/x509/sct.test.ts b/packages/core/src/__tests__/x509/sct.test.ts index 559d46d15..f3670f0f5 100644 --- a/packages/core/src/__tests__/x509/sct.test.ts +++ b/packages/core/src/__tests__/x509/sct.test.ts @@ -15,6 +15,7 @@ limitations under the License. */ import * as crypto from '../../crypto'; import { SignedCertificateTimestamp } from '../../x509/sct'; +import { base64ToUint8Array, hexToUint8Array } from '../../encoding'; describe('SignedCertificateTimestamp', () => { // These are values from a real SCT extension @@ -23,7 +24,7 @@ describe('SignedCertificateTimestamp', () => { const timestamp = '0000018227c09e9c'; const signature = '3045022100b9ecb0b5286feea20d442a409da8c5260bd6ae76b311d71faceff1c7fc93c85c02204e35e55d629a1a84f9a885e7621d9b3af9ed8e7ffd0260679139bda764c5e7d0'; - const sctBuffer = Buffer.from( + const sctBuffer = hexToUint8Array( '00' + // version logID + // logID timestamp + // timestamp @@ -31,8 +32,7 @@ describe('SignedCertificateTimestamp', () => { '04' + // hashAlgorithm '03' + // signatureAlgorithm '0047' + // signatureLength - signature, // signature - 'hex' + signature // signature ); describe('#parse', () => { @@ -41,12 +41,12 @@ describe('SignedCertificateTimestamp', () => { const sct = SignedCertificateTimestamp.parse(sctBuffer); expect(sct.version).toEqual(0x00); - expect(sct.logID).toStrictEqual(Buffer.from(logID, 'hex')); - expect(sct.timestamp).toStrictEqual(Buffer.from(timestamp, 'hex')); + expect(sct.logID).toStrictEqual(hexToUint8Array(logID)); + expect(sct.timestamp).toStrictEqual(hexToUint8Array(timestamp)); expect(sct.extensions).toHaveLength(0); expect(sct.hashAlgorithm).toEqual(0x04); expect(sct.signatureAlgorithm).toEqual(0x03); - expect(sct.signature).toStrictEqual(Buffer.from(signature, 'hex')); + expect(sct.signature).toStrictEqual(hexToUint8Array(signature)); }); }); @@ -54,13 +54,13 @@ describe('SignedCertificateTimestamp', () => { describe('when the SCT buffer is too short', () => { it('throws an error', () => { expect(() => - SignedCertificateTimestamp.parse(Buffer.from('')) + SignedCertificateTimestamp.parse(hexToUint8Array('')) ).toThrow('request past end of buffer'); }); }); describe('when the SCT buffer is too long', () => { - const sctBuffer = Buffer.from( + const sctBuffer = hexToUint8Array( '00' + logID + timestamp + @@ -69,8 +69,7 @@ describe('SignedCertificateTimestamp', () => { '03' + '0047' + signature + - 'DEADBEEF', // extra bytes - 'hex' + 'DEADBEEF' // extra bytes ); it('throws an error', () => { @@ -100,19 +99,15 @@ describe('SignedCertificateTimestamp', () => { describe('#verify', () => { // Real pre-certificate used to generate the SCT - const preCert = Buffer.from( - 'c355ee53d69e68aade04e5c6cc202cfac11fbcaa67e9a2ba7a64ced2aec8ccd000019b30820197a0030201020214466f689fbcc3be13e63ddbd14a277c41cd56d271300a06082a8648ce3d040303303731153013060355040a130c73696773746f72652e646576311e301c0603550403131573696773746f72652d696e7465726d656469617465301e170d3232303732323231313135315a170d3232303732323231323135315a30003059301306072a8648ce3d020106082a8648ce3d0301070342000459f2ab2bc2b2f9db98e711207b1c61d9f852fba456c40a1dcdd690de9ef9c2fba6133a565ccca76afdeea6352a1b0dbcf993e74e901892bca4ff3977a4a45410a381b73081b4300e0603551d0f0101ff04040302078030130603551d25040c300a06082b06010505070303301d0603551d0e041604141ce0136e2e5cdf1b097582a9326905ffc40f557f301f0603551d23041830168014dfd3e9cf56241196f9a8d8e92855a2c62e18643f301f0603551d110101ff041530138111627269616e40646568616d65722e636f6d302c060a2b0601040183bf300101041e68747470733a2f2f6769746875622e636f6d2f6c6f67696e2f6f61757468', - 'hex' - ); + const preCert = hexToUint8Array( + 'c355ee53d69e68aade04e5c6cc202cfac11fbcaa67e9a2ba7a64ced2aec8ccd000019b30820197a0030201020214466f689fbcc3be13e63ddbd14a277c41cd56d271300a06082a8648ce3d040303303731153013060355040a130c73696773746f72652e646576311e301c0603550403131573696773746f72652d696e7465726d656469617465301e170d3232303732323231313135315a170d3232303732323231323135315a30003059301306072a8648ce3d020106082a8648ce3d0301070342000459f2ab2bc2b2f9db98e711207b1c61d9f852fba456c40a1dcdd690de9ef9c2fba6133a565ccca76afdeea6352a1b0dbcf993e74e901892bca4ff3977a4a45410a381b73081b4300e0603551d0f0101ff04040302078030130603551d25040c300a06082b06010505070303301d0603551d0e041604141ce0136e2e5cdf1b097582a9326905ffc40f557f301f0603551d23041830168014dfd3e9cf56241196f9a8d8e92855a2c62e18643f301f0603551d110101ff041530138111627269616e40646568616d65722e636f6d302c060a2b0601040183bf300101041e68747470733a2f2f6769746875622e636f6d2f6c6f67696e2f6f61757468' ); const subject = SignedCertificateTimestamp.parse(sctBuffer); // Real key used to sign the SCT const key = crypto.createPublicKey( - Buffer.from( - 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEbfwR+RJudXscgRBRpKX1XFDy3PyudDxz/SfnRi1fT8ekpfBd2O1uoz7jr3Z8nKzxA69EUQ+eFCFI3zeubPWU7w==', - 'base64' - ) + base64ToUint8Array( + 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEbfwR+RJudXscgRBRpKX1XFDy3PyudDxz/SfnRi1fT8ekpfBd2O1uoz7jr3Z8nKzxA69EUQ+eFCFI3zeubPWU7w==' ) ); describe('when the signature is valid', () => { @@ -122,7 +117,7 @@ describe('SignedCertificateTimestamp', () => { }); describe('when the signature is invalid', () => { - const preCert = Buffer.from('deadbeaf', 'hex'); + const preCert = hexToUint8Array('deadbeaf'); it('returns false', () => { expect(subject.verify(preCert, key)).toEqual(false); diff --git a/packages/core/src/asn1/length.ts b/packages/core/src/asn1/length.ts index b8cdeaa2f..6da551c31 100644 --- a/packages/core/src/asn1/length.ts +++ b/packages/core/src/asn1/length.ts @@ -52,9 +52,9 @@ export function decodeLength(stream: ByteStream): number { } // Translates the supplied value to a DER-encoded length. -export function encodeLength(len: number): Buffer { +export function encodeLength(len: number): Uint8Array { if (len < 128) { - return Buffer.from([len]); + return new Uint8Array([len]); } // Bitwise operations on large numbers are not supported in JS, so we need to @@ -67,5 +67,5 @@ export function encodeLength(len: number): Buffer { val = val >> 8n; } - return Buffer.from([0x80 | bytes.length, ...bytes]); + return new Uint8Array([0x80 | bytes.length, ...bytes]); } diff --git a/packages/core/src/asn1/obj.ts b/packages/core/src/asn1/obj.ts index e5bf99884..2d257624c 100644 --- a/packages/core/src/asn1/obj.ts +++ b/packages/core/src/asn1/obj.ts @@ -28,20 +28,20 @@ import { ASN1Tag } from './tag'; export class ASN1Obj { readonly tag: ASN1Tag; readonly subs: ASN1Obj[]; - readonly value: Buffer; + readonly value: Uint8Array; - constructor(tag: ASN1Tag, value: Buffer, subs: ASN1Obj[]) { + constructor(tag: ASN1Tag, value: Uint8Array, subs: ASN1Obj[]) { this.tag = tag; this.value = value; this.subs = subs; } // Constructs an ASN.1 object from a Buffer of DER-encoded bytes. - public static parseBuffer(buf: Buffer): ASN1Obj { + public static parseBuffer(buf: Uint8Array): ASN1Obj { return parseStream(new ByteStream(buf)); } - public toDER(): Buffer { + public toDER(): Uint8Array { const valueStream = new ByteStream(); if (this.subs.length > 0) { diff --git a/packages/core/src/asn1/parse.ts b/packages/core/src/asn1/parse.ts index 1a51c7c5f..41e9ed026 100644 --- a/packages/core/src/asn1/parse.ts +++ b/packages/core/src/asn1/parse.ts @@ -13,6 +13,9 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ + +import { uint8ArrayToString } from '../encoding'; + const RE_TIME_SHORT_YEAR = /^(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(\.\d{3})?Z$/; const RE_TIME_LONG_YEAR = @@ -20,7 +23,7 @@ const RE_TIME_LONG_YEAR = // Parse a BigInt from the DER-encoded buffer // https://learn.microsoft.com/en-us/windows/win32/seccertenroll/about-integer -export function parseInteger(buf: Buffer): bigint { +export function parseInteger(buf: Uint8Array): bigint { let pos = 0; const end = buf.length; let val = buf[pos]; @@ -51,13 +54,13 @@ export function parseInteger(buf: Buffer): bigint { // Parse an ASCII string from the DER-encoded buffer // https://learn.microsoft.com/en-us/windows/win32/seccertenroll/about-basic-types#boolean -export function parseStringASCII(buf: Buffer): string { - return buf.toString('ascii'); +export function parseStringASCII(buf: Uint8Array): string { + return uint8ArrayToString(buf); } // Parse a Date from the DER-encoded buffer // https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.5.1 -export function parseTime(buf: Buffer, shortYear: boolean): Date { +export function parseTime(buf: Uint8Array, shortYear: boolean): Date { const timeStr = parseStringASCII(buf); // Parse the time string into matches - captured groups start at index 1 @@ -82,7 +85,7 @@ export function parseTime(buf: Buffer, shortYear: boolean): Date { // Parse an OID from the DER-encoded buffer // https://learn.microsoft.com/en-us/windows/win32/seccertenroll/about-object-identifier -export function parseOID(buf: Buffer): string { +export function parseOID(buf: Uint8Array): string { let pos = 0; const end = buf.length; @@ -112,13 +115,13 @@ export function parseOID(buf: Buffer): string { // Parse a boolean from the DER-encoded buffer // https://learn.microsoft.com/en-us/windows/win32/seccertenroll/about-basic-types#boolean -export function parseBoolean(buf: Buffer): boolean { +export function parseBoolean(buf: Uint8Array): boolean { return buf[0] !== 0; } // Parse a bit string from the DER-encoded buffer // https://learn.microsoft.com/en-us/windows/win32/seccertenroll/about-bit-string -export function parseBitString(buf: Buffer): number[] { +export function parseBitString(buf: Uint8Array): number[] { // First byte tell us how many unused bits are in the last byte const unused = buf[0]; diff --git a/packages/core/src/crypto.ts b/packages/core/src/crypto.ts index f97a08442..7daed9732 100644 --- a/packages/core/src/crypto.ts +++ b/packages/core/src/crypto.ts @@ -19,17 +19,19 @@ export type { KeyObject } from 'crypto'; const SHA256_ALGORITHM = 'sha256'; export function createPublicKey( - key: string | Buffer, + keyValue: string | Uint8Array, type: 'spki' | 'pkcs1' = 'spki' ): crypto.KeyObject { - if (typeof key === 'string') { + if (typeof keyValue === 'string') { + const key = keyValue; return crypto.createPublicKey(key); } else { + const key = Buffer.from(keyValue); return crypto.createPublicKey({ key, format: 'der', type: type }); } } -export function digest(algorithm: string, ...data: BinaryLike[]): Buffer { +export function digest(algorithm: string, ...data: BinaryLike[]): Uint8Array { const hash = crypto.createHash(algorithm); for (const d of data) { hash.update(d); @@ -38,7 +40,7 @@ export function digest(algorithm: string, ...data: BinaryLike[]): Buffer { } // TODO: deprecate this in favor of digest() -export function hash(...data: BinaryLike[]): Buffer { +export function hash(...data: BinaryLike[]): Uint8Array { const hash = crypto.createHash(SHA256_ALGORITHM); for (const d of data) { hash.update(d); @@ -47,9 +49,9 @@ export function hash(...data: BinaryLike[]): Buffer { } export function verify( - data: Buffer, + data: Uint8Array, key: crypto.KeyLike, - signature: Buffer, + signature: Uint8Array, algorithm?: string ): boolean { // The try/catch is to work around an issue in Node 14.x where verify throws @@ -62,7 +64,7 @@ export function verify( } } -export function bufferEqual(a: Buffer, b: Buffer): boolean { +export function bufferEqual(a: Uint8Array, b: Uint8Array): boolean { try { return crypto.timingSafeEqual(a, b); } catch { diff --git a/packages/core/src/dsse.ts b/packages/core/src/dsse.ts index a625f584e..ba30daef7 100644 --- a/packages/core/src/dsse.ts +++ b/packages/core/src/dsse.ts @@ -16,7 +16,7 @@ limitations under the License. const PAE_PREFIX = 'DSSEv1'; // DSSE Pre-Authentication Encoding -export function preAuthEncoding(payloadType: string, payload: Buffer): Buffer { +export function preAuthEncoding(payloadType: string, payload: Uint8Array): Uint8Array { const prefix = [ PAE_PREFIX, payloadType.length, @@ -25,5 +25,14 @@ export function preAuthEncoding(payloadType: string, payload: Buffer): Buffer { '', ].join(' '); - return Buffer.concat([Buffer.from(prefix, 'ascii'), payload]); -} + // Is using utf-8 a problem? I don't think so but adding this warning + const encoder = new TextEncoder(); + const prefixBuffer = encoder.encode(prefix) + + // Badic Uint8Array concat + const combinedArray = new Uint8Array(prefixBuffer.length + payload.length); + + combinedArray.set(prefixBuffer, 0); + combinedArray.set(payload, prefixBuffer.length); + return combinedArray; +} \ No newline at end of file diff --git a/packages/core/src/encoding.ts b/packages/core/src/encoding.ts index d94874a4b..1659d3186 100644 --- a/packages/core/src/encoding.ts +++ b/packages/core/src/encoding.ts @@ -13,13 +13,92 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -const BASE64_ENCODING = 'base64'; -const UTF8_ENCODING = 'utf-8'; +export function base64ToUint8Array(base64: string): Uint8Array { + const binaryString = atob(base64); + const length = binaryString.length; + const bytes = new Uint8Array(length); + + for (let i = 0; i < length; i++) { + bytes[i] = binaryString.charCodeAt(i); // Convert binary string to byte array + } + + return bytes; +} + +export function uint8ArrayToBase64(uint8Array: Uint8Array): string { + let binaryString = ''; + + for (let i = 0; i < uint8Array.length; i++) { + binaryString += String.fromCharCode(uint8Array[i]); + } + + return btoa(binaryString); +} + +export function hexToUint8Array(hex: string): Uint8Array { + if (hex.length % 2 !== 0) { + throw new Error('Hex string must have an even length'); + } + + const length = hex.length / 2; + const uint8Array = new Uint8Array(length); + + for (let i = 0; i < length; i++) { + uint8Array[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16); + } + + return uint8Array; +} + + export function uint8ArrayToHex(uint8Array: Uint8Array): string { + let hexString = ''; + + for (let i = 0; i < uint8Array.length; i++) { + let hex = uint8Array[i].toString(16); + if (hex.length === 1) { + hex = '0' + hex; + } + hexString += hex; + } + + return hexString; +} + +export function stringToUint8Array(str: string): Uint8Array { + // Defaults to utf-8, but utf-8 is ascii compatible + const encoder = new TextEncoder(); + return encoder.encode(str); +} + +// This is silly, but it is a hack to be consistent with the original test suite +export function uint8ArrayToString(uint8Array: Uint8Array | undefined): string | undefined { + if (!uint8Array) { + return undefined; + } + const decoder = new TextDecoder("ascii"); + return decoder.decode(uint8Array); +} + +export function readBigInt64BE(uint8Array: Uint8Array, offset?: number): bigint { + if (!offset) { + offset = 0; + } + const high = uint8Array[offset] << 24 | + uint8Array[offset + 1] << 16 | + uint8Array[offset + 2] << 8 | + uint8Array[offset + 3]; + const low = uint8Array[offset + 4] << 24 | + uint8Array[offset + 5] << 16 | + uint8Array[offset + 6] << 8 | + uint8Array[offset + 7]; + const value = (BigInt(high) << BigInt(32)) + BigInt(low); + return value; +} export function base64Encode(str: string): string { - return Buffer.from(str, UTF8_ENCODING).toString(BASE64_ENCODING); + return uint8ArrayToBase64(stringToUint8Array(str)); } export function base64Decode(str: string): string { - return Buffer.from(str, BASE64_ENCODING).toString(UTF8_ENCODING); -} + return uint8ArrayToString(base64ToUint8Array(str)); +} \ No newline at end of file diff --git a/packages/core/src/pem.ts b/packages/core/src/pem.ts index a658d56b7..ab4f904ea 100644 --- a/packages/core/src/pem.ts +++ b/packages/core/src/pem.ts @@ -13,10 +13,13 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ + +import { base64ToUint8Array, uint8ArrayToBase64 } from './encoding'; + const PEM_HEADER = /-----BEGIN (.*)-----/; const PEM_FOOTER = /-----END (.*)-----/; -export function toDER(certificate: string): Buffer { +export function toDER(certificate: string): Uint8Array { let der = ''; certificate.split('\n').forEach((line) => { @@ -27,15 +30,15 @@ export function toDER(certificate: string): Buffer { der += line; }); - return Buffer.from(der, 'base64'); + return base64ToUint8Array(der); } // Translates a DER-encoded buffer into a PEM-encoded string. Standard PEM // encoding dictates that each certificate should have a trailing newline after // the footer. -export function fromDER(certificate: Buffer, type = 'CERTIFICATE'): string { +export function fromDER(certificate: Uint8Array, type = 'CERTIFICATE'): string { // Base64-encode the certificate. - const der = certificate.toString('base64'); + const der = uint8ArrayToBase64(certificate); // Split the certificate into lines of 64 characters. const lines = der.match(/.{1,64}/g) || ''; diff --git a/packages/core/src/rfc3161/timestamp.ts b/packages/core/src/rfc3161/timestamp.ts index 0ed80c0b3..63b677c0c 100644 --- a/packages/core/src/rfc3161/timestamp.ts +++ b/packages/core/src/rfc3161/timestamp.ts @@ -30,7 +30,7 @@ export class RFC3161Timestamp { this.root = asn1; } - public static parse(der: Buffer): RFC3161Timestamp { + public static parse(der: Uint8Array): RFC3161Timestamp { const asn1 = ASN1Obj.parseBuffer(der); return new RFC3161Timestamp(asn1); } @@ -51,11 +51,11 @@ export class RFC3161Timestamp { return this.tstInfo.genTime; } - get signerIssuer(): Buffer { + get signerIssuer(): Uint8Array { return this.signerSidObj.subs[0].value; } - get signerSerialNumber(): Buffer { + get signerSerialNumber(): Uint8Array { return this.signerSidObj.subs[1].value; } @@ -69,7 +69,7 @@ export class RFC3161Timestamp { return ECDSA_SIGNATURE_ALGOS[oid]; } - get signatureValue(): Buffer { + get signatureValue(): Uint8Array { return this.signatureValueObj.value; } @@ -78,7 +78,7 @@ export class RFC3161Timestamp { return new TSTInfo(this.eContentObj.subs[0].subs[0]); } - public verify(data: Buffer, publicKey: crypto.KeyObject): void { + public verify(data: Uint8Array, publicKey: crypto.KeyObject): void { if (!this.timeStampTokenObj) { throw new RFC3161TimestampVerificationError('timeStampToken is missing'); } diff --git a/packages/core/src/rfc3161/tstinfo.ts b/packages/core/src/rfc3161/tstinfo.ts index 96fbd75a6..ed58b1074 100644 --- a/packages/core/src/rfc3161/tstinfo.ts +++ b/packages/core/src/rfc3161/tstinfo.ts @@ -38,15 +38,15 @@ export class TSTInfo { return SHA2_HASH_ALGOS[oid]; } - get messageImprintHashedMessage(): Buffer { + get messageImprintHashedMessage(): Uint8Array { return this.messageImprintObj.subs[1].value; } - get raw(): Buffer { + get raw(): Uint8Array { return this.root.toDER(); } - public verify(data: Buffer): void { + public verify(data: Uint8Array): void { const digest = crypto.digest(this.messageImprintHashAlgorithm, data); if (!crypto.bufferEqual(digest, this.messageImprintHashedMessage)) { throw new RFC3161TimestampVerificationError( diff --git a/packages/core/src/stream.ts b/packages/core/src/stream.ts index d822cdabf..92f89b5d0 100644 --- a/packages/core/src/stream.ts +++ b/packages/core/src/stream.ts @@ -19,20 +19,20 @@ export class ByteStream { private static BLOCK_SIZE = 1024; private buf: ArrayBuffer; - private view: Buffer; + private view: Uint8Array; private start = 0; constructor(buffer?: ArrayBuffer) { if (buffer) { this.buf = buffer; - this.view = Buffer.from(buffer); + this.view = new Uint8Array(buffer); } else { this.buf = new ArrayBuffer(0); - this.view = Buffer.from(this.buf); + this.view = new Uint8Array(this.buf); } } - get buffer(): Buffer { + get buffer(): Uint8Array { return this.view.subarray(0, this.start); } @@ -50,7 +50,7 @@ export class ByteStream { // Returns a Buffer containing the specified number of bytes starting at the // given start position. - public slice(start: number, len: number): Buffer { + public slice(start: number, len: number): Uint8Array { const end = start + len; if (end > this.length) { @@ -95,9 +95,9 @@ export class ByteStream { this.start += view.length; } - public getBlock(size: number): Buffer { + public getBlock(size: number): Uint8Array { if (size <= 0) { - return Buffer.alloc(0); + return new Uint8Array(0); } if (this.start + size > this.view.length) { @@ -130,7 +130,7 @@ export class ByteStream { private realloc(size: number) { const newArray = new ArrayBuffer(size); - const newView = Buffer.from(newArray); + const newView = new Uint8Array(newArray); // Copy the old buffer into the new one newView.set(this.view); diff --git a/packages/core/src/x509/cert.ts b/packages/core/src/x509/cert.ts index 69a1c0f05..bef3dd9d2 100644 --- a/packages/core/src/x509/cert.ts +++ b/packages/core/src/x509/cert.ts @@ -41,7 +41,7 @@ export class X509Certificate { this.root = asn1; } - public static parse(cert: Buffer | string): X509Certificate { + public static parse(cert: Uint8Array | string): X509Certificate { const der = typeof cert === 'string' ? pem.toDER(cert) : cert; const asn1 = ASN1Obj.parseBuffer(der); return new X509Certificate(asn1); @@ -57,7 +57,7 @@ export class X509Certificate { return `v${(ver + BigInt(1)).toString()}`; } - get serialNumber(): Buffer { + get serialNumber(): Uint8Array { return this.serialNumberObj.value; } @@ -71,15 +71,15 @@ export class X509Certificate { return this.validityObj.subs[1].toDate(); } - get issuer(): Buffer { + get issuer(): Uint8Array { return this.issuerObj.value; } - get subject(): Buffer { + get subject(): Uint8Array { return this.subjectObj.value; } - get publicKey(): Buffer { + get publicKey(): Uint8Array { return this.subjectPublicKeyInfoObj.toDER(); } @@ -88,7 +88,7 @@ export class X509Certificate { return ECDSA_SIGNATURE_ALGOS[oid]; } - get signatureValue(): Buffer { + get signatureValue(): Uint8Array { // Signature value is a bit string, so we need to skip the first byte return this.signatureValueObj.value.subarray(1); } @@ -171,14 +171,13 @@ export class X509Certificate { } public equals(other: X509Certificate): boolean { - return this.root.toDER().equals(other.root.toDER()); + return crypto.bufferEqual(this.root.toDER(), other.root.toDER()); } // Creates a copy of the certificate with a new buffer public clone(): X509Certificate { const der = this.root.toDER(); - const clone = Buffer.alloc(der.length); - der.copy(clone); + const clone = new Uint8Array(der); return X509Certificate.parse(clone); } diff --git a/packages/core/src/x509/ext.ts b/packages/core/src/x509/ext.ts index adb9e464d..663ae904e 100644 --- a/packages/core/src/x509/ext.ts +++ b/packages/core/src/x509/ext.ts @@ -16,6 +16,7 @@ limitations under the License. import { ASN1Obj } from '../asn1'; import { ByteStream } from '../stream'; import { SignedCertificateTimestamp } from './sct'; +import { uint8ArrayToString } from '../encoding'; // https://www.rfc-editor.org/rfc/rfc5280#section-4.1 export class X509Extension { @@ -35,7 +36,7 @@ export class X509Extension { return this.root.subs.length === 3 ? this.root.subs[1].toBoolean() : false; } - get value(): Buffer { + get value(): Uint8Array { return this.extnValueObj.value; } @@ -92,11 +93,11 @@ export class X509KeyUsageExtension extends X509Extension { // https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.6 export class X509SubjectAlternativeNameExtension extends X509Extension { get rfc822Name(): string | undefined { - return this.findGeneralName(0x01)?.value.toString('ascii'); + return uint8ArrayToString(this.findGeneralName(0x01)?.value); } get uri(): string | undefined { - return this.findGeneralName(0x06)?.value.toString('ascii'); + return uint8ArrayToString(this.findGeneralName(0x06)?.value); } // Retrieve the value of an otherName with the given OID. @@ -116,7 +117,7 @@ export class X509SubjectAlternativeNameExtension extends X509Extension { // The otherNameValue is a sequence containing the actual value. const otherNameValue = otherName.subs[1]; - return otherNameValue.subs[0].value.toString('ascii'); + return uint8ArrayToString(otherNameValue.subs[0].value); } private findGeneralName(tag: number): ASN1Obj | undefined { @@ -131,7 +132,7 @@ export class X509SubjectAlternativeNameExtension extends X509Extension { // https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.1 export class X509AuthorityKeyIDExtension extends X509Extension { - get keyIdentifier(): Buffer | undefined { + get keyIdentifier(): Uint8Array | undefined { return this.findSequenceMember(0x00)?.value; } @@ -147,7 +148,7 @@ export class X509AuthorityKeyIDExtension extends X509Extension { // https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.2 export class X509SubjectKeyIDExtension extends X509Extension { - get keyIdentifier(): Buffer { + get keyIdentifier(): Uint8Array { return this.extnValueObj.subs[0].value; } } diff --git a/packages/core/src/x509/sct.ts b/packages/core/src/x509/sct.ts index bd8e52ff9..370f3aada 100644 --- a/packages/core/src/x509/sct.ts +++ b/packages/core/src/x509/sct.ts @@ -15,25 +15,26 @@ limitations under the License. */ import * as crypto from '../crypto'; import { ByteStream } from '../stream'; +import { readBigInt64BE } from '../encoding'; interface SCTOptions { version: number; - logID: Buffer; - timestamp: Buffer; - extensions: Buffer; + logID: Uint8Array; + timestamp: Uint8Array; + extensions: Uint8Array; hashAlgorithm: number; signatureAlgorithm: number; - signature: Buffer; + signature: Uint8Array; } export class SignedCertificateTimestamp { readonly version: number; - readonly logID: Buffer; - readonly timestamp: Buffer; - readonly extensions: Buffer; + readonly logID: Uint8Array; + readonly timestamp: Uint8Array; + readonly extensions: Uint8Array; readonly hashAlgorithm: number; readonly signatureAlgorithm: number; - readonly signature: Buffer; + readonly signature: Uint8Array; constructor(options: SCTOptions) { this.version = options.version; @@ -46,7 +47,7 @@ export class SignedCertificateTimestamp { } get datetime(): Date { - return new Date(Number(this.timestamp.readBigInt64BE())); + return new Date(Number(readBigInt64BE(this.timestamp))); } // Returns the hash algorithm used to generate the SCT's signature. @@ -79,7 +80,7 @@ export class SignedCertificateTimestamp { } } - public verify(preCert: Buffer, key: crypto.KeyObject): boolean { + public verify(preCert: Uint8Array, key: crypto.KeyObject): boolean { // Assemble the digitally-signed struct (the data over which the signature // was generated). // https://www.rfc-editor.org/rfc/rfc6962#section-3.2 @@ -104,7 +105,7 @@ export class SignedCertificateTimestamp { // specified as part of the SCT and TLS specs. // https://www.rfc-editor.org/rfc/rfc6962#section-3.2 // https://www.rfc-editor.org/rfc/rfc5246#section-7.4.1.4.1 - public static parse(buf: Buffer): SignedCertificateTimestamp { + public static parse(buf: Uint8Array): SignedCertificateTimestamp { const stream = new ByteStream(buf); // Version - enum { v1(0), (255) }