Use asn1 classes from webcrypto-core

This commit is contained in:
microshine 2020-04-06 15:21:38 +03:00
parent d4f103e44e
commit cf77b2e013
21 changed files with 49 additions and 544 deletions

View File

@ -68,7 +68,6 @@
"dependencies": {
"@peculiar/asn1-schema": "^1.0.5",
"@peculiar/json-schema": "^1.1.10",
"asn1js": "^2.0.26",
"pvtsutils": "^1.0.10",
"tslib": "^1.11.1",
"webcrypto-core": "^1.0.19-next.0"

View File

@ -1,31 +0,0 @@
import { AsnProp, AsnPropTypes } from "@peculiar/asn1-schema";
// RFC 5280
// https://tools.ietf.org/html/rfc5280#section-4.1.1.2
//
// AlgorithmIdentifier ::= SEQUENCE {
// algorithm OBJECT IDENTIFIER,
// parameters ANY DEFINED BY algorithm OPTIONAL }
// -- contains a value of the type
// -- registered for use with the
// -- algorithm object identifier value
export type ParametersType = ArrayBuffer | null;
export class AlgorithmIdentifier {
@AsnProp({
type: AsnPropTypes.ObjectIdentifier,
})
public algorithm!: string;
@AsnProp({
type: AsnPropTypes.Any,
optional: true,
})
public parameters?: ParametersType;
constructor(params?: Partial<AlgorithmIdentifier>) {
Object.assign(this, params);
}
}

View File

@ -1,54 +0,0 @@
import { AsnIntegerConverter, AsnProp, AsnPropTypes, AsnSerializer } from "@peculiar/asn1-schema";
import { IJsonConvertible } from "@peculiar/json-schema";
import { Convert } from "pvtsutils";
import { EcPublicKey } from "./ec_public_key";
// RFC 5915
// https://tools.ietf.org/html/rfc5915#section-3
//
// ECPrivateKey ::= SEQUENCE {
// version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
// privateKey OCTET STRING,
// parameters [0] ECParameters {{ NamedCurve }} OPTIONAL,
// publicKey [1] BIT STRING OPTIONAL
// }
export class EcPrivateKey implements IJsonConvertible {
@AsnProp({ type: AsnPropTypes.Integer, converter: AsnIntegerConverter })
public version = 1;
@AsnProp({ type: AsnPropTypes.OctetString })
public privateKey = new ArrayBuffer(0);
@AsnProp({ context: 0, type: AsnPropTypes.Any, optional: true })
public parameters?: ArrayBuffer;
@AsnProp({ context: 1, type: AsnPropTypes.BitString, optional: true })
public publicKey?: ArrayBuffer;
public fromJSON(json: any): this {
if (!("d" in json)) {
throw new Error("d: Missing required property");
}
this.privateKey = Convert.FromBase64Url(json.d);
if ("x" in json) {
const publicKey = new EcPublicKey();
publicKey.fromJSON(json);
this.publicKey = AsnSerializer.toASN(publicKey).valueBlock.valueHex;
}
return this;
}
public toJSON() {
const jwk: JsonWebKey = {};
jwk.d = Convert.ToBase64Url(this.privateKey);
if (this.publicKey) {
Object.assign(jwk, new EcPublicKey(this.publicKey).toJSON());
}
return jwk;
}
}

View File

@ -1,64 +0,0 @@
import { AsnProp, AsnPropTypes, AsnType, AsnTypeTypes } from "@peculiar/asn1-schema";
import { IJsonConvertible } from "@peculiar/json-schema";
import { Convert } from "pvtsutils";
import * as core from "webcrypto-core";
// RFC 5480
// https://tools.ietf.org/html/rfc5480#section-2.2
//
// ECPoint ::= OCTET STRING
@AsnType({ type: AsnTypeTypes.Choice })
export class EcPublicKey implements IJsonConvertible {
@AsnProp({ type: AsnPropTypes.OctetString })
public value = new ArrayBuffer(0);
constructor(value?: ArrayBuffer) {
if (value) {
this.value = value;
}
}
public toJSON() {
let bytes = new Uint8Array(this.value);
if (bytes[0] !== 0x04) {
throw new core.CryptoError("Wrong ECPoint. Current version supports only Uncompressed (0x04) point");
}
bytes = new Uint8Array(this.value.slice(1));
const size = bytes.length / 2;
const offset = 0;
const json = {
x: Convert.ToBase64Url(bytes.buffer.slice(offset, offset + size)),
y: Convert.ToBase64Url(bytes.buffer.slice(offset + size, offset + size + size)),
};
return json;
}
public fromJSON(json: any): this {
if (!("x" in json)) {
throw new Error("x: Missing required property");
}
if (!("y" in json)) {
throw new Error("y: Missing required property");
}
const x = Convert.FromBase64Url(json.x);
const y = Convert.FromBase64Url(json.y);
const value = Buffer.concat([
new Uint8Array([0x04]), // uncompressed bit
new Uint8Array(x),
new Uint8Array(y),
]);
this.value = new Uint8Array(value).buffer;
return this;
}
}

View File

@ -1,39 +0,0 @@
import { AsnProp, AsnPropTypes, IAsnConverter } from "@peculiar/asn1-schema";
// @ts-ignore
import * as asn1 from "asn1js";
// RFC 3279
// https://tools.ietf.org/html/rfc3279#section-2.2.3
//
// ECDSA-Sig-Value ::= SEQUENCE {
// r INTEGER,
// s INTEGER
// }
export const AsnIntegerWithoutPaddingConverter: IAsnConverter<ArrayBuffer> = {
fromASN: (value: any) => {
const bytes = new Uint8Array(value.valueBlock.valueHex);
return (bytes[0] === 0)
? bytes.buffer.slice(1)
: bytes.buffer;
},
toASN: (value: ArrayBuffer) => {
const bytes = new Uint8Array(value);
if (bytes[0] > 127) {
const newValue = new Uint8Array(bytes.length + 1);
newValue.set(bytes, 1);
return new asn1.Integer({ valueHex: newValue });
}
return new asn1.Integer({ valueHex: value });
},
};
export class EcDsaSignature {
@AsnProp({ type: AsnPropTypes.Integer, converter: AsnIntegerWithoutPaddingConverter })
public r = new ArrayBuffer(0);
@AsnProp({ type: AsnPropTypes.Integer, converter: AsnIntegerWithoutPaddingConverter })
public s = new ArrayBuffer(0);
}

View File

@ -1,9 +0,0 @@
export * from "./object_identifier";
export * from "./algorithm_identifier";
export * from "./private_key_info";
export * from "./public_key_info";
export * from "./rsa_private_key";
export * from "./rsa_public_key";
export * from "./ec_private_key";
export * from "./ec_public_key";
export * from "./ec_signature";

View File

@ -1,14 +0,0 @@
import { AsnProp, AsnPropTypes, AsnType, AsnTypeTypes } from "@peculiar/asn1-schema";
@AsnType({ type: AsnTypeTypes.Choice })
export class ObjectIdentifier {
@AsnProp({type: AsnPropTypes.ObjectIdentifier})
public value!: string;
constructor(value?: string) {
if (value) {
this.value = value;
}
}
}

View File

@ -1,35 +0,0 @@
import { AsnProp, AsnPropTypes } from "@peculiar/asn1-schema";
import { AlgorithmIdentifier } from "./algorithm_identifier";
// RFC 5208
// https://tools.ietf.org/html/rfc5208#section-5
//
// PrivateKeyInfo ::= SEQUENCE {
// version Version,
// privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
// privateKey PrivateKey,
// attributes [0] IMPLICIT Attributes OPTIONAL }
//
// Version ::= INTEGER
//
// PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
//
// PrivateKey ::= OCTET STRING
//
// Attributes ::= SET OF Attribute
export class PrivateKeyInfo {
@AsnProp({ type: AsnPropTypes.Integer })
public version = 0;
@AsnProp({ type: AlgorithmIdentifier })
public privateKeyAlgorithm = new AlgorithmIdentifier();
@AsnProp({ type: AsnPropTypes.OctetString })
public privateKey = new ArrayBuffer(0);
@AsnProp({ type: AsnPropTypes.Any, optional: true })
public attributes?: ArrayBuffer;
}

View File

@ -1,19 +0,0 @@
import { AsnProp, AsnPropTypes } from "@peculiar/asn1-schema";
import { AlgorithmIdentifier } from "./algorithm_identifier";
// RFC 5280
// https://tools.ietf.org/html/rfc5280#section-4.1
//
// SubjectPublicKeyInfo ::= SEQUENCE {
// algorithm AlgorithmIdentifier,
// subjectPublicKey BIT STRING
export class PublicKeyInfo {
@AsnProp({ type: AlgorithmIdentifier })
public publicKeyAlgorithm = new AlgorithmIdentifier();
@AsnProp({ type: AsnPropTypes.BitString })
public publicKey = new ArrayBuffer(0);
}

View File

@ -1,61 +0,0 @@
import { AsnIntegerConverter, AsnProp, AsnPropTypes } from "@peculiar/asn1-schema";
import { JsonProp } from "@peculiar/json-schema";
import { AsnIntegerArrayBufferConverter, JsonBase64UrlArrayBufferConverter } from "../converters";
// RFC 3437
// https://tools.ietf.org/html/rfc3447#appendix-A.1.2
//
// RSAPrivateKey ::= SEQUENCE {
// version Version,
// modulus INTEGER, -- n
// publicExponent INTEGER, -- e
// privateExponent INTEGER, -- d
// prime1 INTEGER, -- p
// prime2 INTEGER, -- q
// exponent1 INTEGER, -- d mod (p-1)
// exponent2 INTEGER, -- d mod (q-1)
// coefficient INTEGER, -- (inverse of q) mod p
// otherPrimeInfos OtherPrimeInfos OPTIONAL
// }
export class RsaPrivateKey {
@AsnProp({ type: AsnPropTypes.Integer, converter: AsnIntegerConverter })
public version = 0;
@AsnProp({ type: AsnPropTypes.Integer, converter: AsnIntegerArrayBufferConverter })
@JsonProp({ name: "n", converter: JsonBase64UrlArrayBufferConverter })
public modulus = new ArrayBuffer(0);
@AsnProp({ type: AsnPropTypes.Integer, converter: AsnIntegerArrayBufferConverter })
@JsonProp({ name: "e", converter: JsonBase64UrlArrayBufferConverter })
public publicExponent = new ArrayBuffer(0);
@AsnProp({ type: AsnPropTypes.Integer, converter: AsnIntegerArrayBufferConverter })
@JsonProp({ name: "d", converter: JsonBase64UrlArrayBufferConverter })
public privateExponent = new ArrayBuffer(0);
@AsnProp({ type: AsnPropTypes.Integer, converter: AsnIntegerArrayBufferConverter })
@JsonProp({ name: "p", converter: JsonBase64UrlArrayBufferConverter })
public prime1 = new ArrayBuffer(0);
@AsnProp({ type: AsnPropTypes.Integer, converter: AsnIntegerArrayBufferConverter })
@JsonProp({ name: "q", converter: JsonBase64UrlArrayBufferConverter })
public prime2 = new ArrayBuffer(0);
@AsnProp({ type: AsnPropTypes.Integer, converter: AsnIntegerArrayBufferConverter })
@JsonProp({ name: "dp", converter: JsonBase64UrlArrayBufferConverter })
public exponent1 = new ArrayBuffer(0);
@AsnProp({ type: AsnPropTypes.Integer, converter: AsnIntegerArrayBufferConverter })
@JsonProp({ name: "dq", converter: JsonBase64UrlArrayBufferConverter })
public exponent2 = new ArrayBuffer(0);
@AsnProp({ type: AsnPropTypes.Integer, converter: AsnIntegerArrayBufferConverter })
@JsonProp({ name: "qi", converter: JsonBase64UrlArrayBufferConverter })
public coefficient = new ArrayBuffer(0);
@AsnProp({ type: AsnPropTypes.Any, optional: true })
public otherPrimeInfos?: ArrayBuffer;
}

View File

@ -1,23 +0,0 @@
import { AsnProp, AsnPropTypes } from "@peculiar/asn1-schema";
import { JsonProp } from "@peculiar/json-schema";
import { AsnIntegerArrayBufferConverter, JsonBase64UrlArrayBufferConverter } from "../converters";
// RFC 3437
// https://tools.ietf.org/html/rfc3447#appendix-A.1.1
//
// RSAPublicKey ::= SEQUENCE {
// modulus INTEGER, -- n
// publicExponent INTEGER, -- e
// }
export class RsaPublicKey {
@AsnProp({ type: AsnPropTypes.Integer, converter: AsnIntegerArrayBufferConverter })
@JsonProp({ name: "n", converter: JsonBase64UrlArrayBufferConverter })
public modulus = new ArrayBuffer(0);
@AsnProp({ type: AsnPropTypes.Integer, converter: AsnIntegerArrayBufferConverter })
@JsonProp({ name: "e", converter: JsonBase64UrlArrayBufferConverter })
public publicExponent = new ArrayBuffer(0);
}

View File

@ -5,8 +5,3 @@ export const JsonBase64UrlConverter: IJsonConverter<Buffer, string> = {
fromJSON: (value: string) => Buffer.from(Convert.FromBase64Url(value)),
toJSON: (value: Buffer) => Convert.ToBase64Url(value),
};
export const JsonBase64UrlArrayBufferConverter: IJsonConverter<ArrayBuffer, string> = {
fromJSON: (value: string) => Convert.FromBase64Url(value),
toJSON: (value: ArrayBuffer) => Convert.ToBase64Url(new Uint8Array(value)),
};

View File

@ -1,2 +1 @@
export * from "./base64_url";
export * from "./integer_converter";

View File

@ -1,18 +0,0 @@
import { IAsnConverter } from "@peculiar/asn1-schema";
// @ts-ignore
import * as asn1 from "asn1js";
export const AsnIntegerArrayBufferConverter: IAsnConverter<ArrayBuffer> = {
fromASN: (value: any) => {
const valueHex = value.valueBlock.valueHex;
return !(new Uint8Array(valueHex)[0])
? value.valueBlock.valueHex.slice(1)
: value.valueBlock.valueHex;
},
toASN: (value: ArrayBuffer) => {
const valueHex = new Uint8Array(value)[0] > 127
? Buffer.concat([Buffer.from([0]), Buffer.from(value)])
: Buffer.from(value);
return new asn1.Integer({ valueHex: new Uint8Array(valueHex).buffer });
},
};

View File

@ -2,8 +2,6 @@ import crypto from "crypto";
import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema";
import { JsonParser, JsonSerializer } from "@peculiar/json-schema";
import * as core from "webcrypto-core";
import * as asn from "../../asn";
import { ObjectIdentifier } from "../../asn";
import { CryptoKey } from "../../keys";
import { getOidByNamedCurve } from "./helper";
import { EcPrivateKey } from "./private_key";
@ -63,7 +61,7 @@ export class EcCrypto {
};
const signature = signer.sign(options);
const ecSignature = AsnParser.parse(signature, asn.EcDsaSignature);
const ecSignature = AsnParser.parse(signature, core.asn1.EcDsaSignature);
const pointSize = this.getPointSize(key.algorithm.namedCurve);
const r = this.addPadding(pointSize, Buffer.from(ecSignature.r));
@ -85,7 +83,7 @@ export class EcCrypto {
key: key.pem,
};
const ecSignature = new asn.EcDsaSignature();
const ecSignature = new core.asn1.EcDsaSignature();
const pointSize = this.getPointSize(key.algorithm.namedCurve);
ecSignature.r = this.removePadding(signature.slice(0, pointSize));
ecSignature.s = this.removePadding(signature.slice(pointSize, pointSize + pointSize));
@ -99,11 +97,11 @@ export class EcCrypto {
const cryptoAlg = this.getOpenSSLNamedCurve((baseKey.algorithm as EcKeyAlgorithm).namedCurve);
const ecdh = crypto.createECDH(cryptoAlg);
const asnPrivateKey = AsnParser.parse(baseKey.data, asn.PrivateKeyInfo);
const asnEcPrivateKey = AsnParser.parse(asnPrivateKey.privateKey, asn.EcPrivateKey);
const asnPrivateKey = AsnParser.parse(baseKey.data, core.asn1.PrivateKeyInfo);
const asnEcPrivateKey = AsnParser.parse(asnPrivateKey.privateKey, core.asn1.EcPrivateKey);
ecdh.setPrivateKey(Buffer.from(asnEcPrivateKey.privateKey));
const asnPublicKey = AsnParser.parse((algorithm.public as CryptoKey).data, asn.PublicKeyInfo);
const asnPublicKey = AsnParser.parse((algorithm.public as CryptoKey).data, core.asn1.PublicKeyInfo);
const bits = ecdh.computeSecret(Buffer.from(asnPublicKey.publicKey));
return new Uint8Array(bits).buffer.slice(0, length >> 3);
@ -117,7 +115,7 @@ export class EcCrypto {
case "spki":
return new Uint8Array(key.data).buffer;
case "raw": {
const publicKeyInfo = AsnParser.parse(key.data, asn.PublicKeyInfo);
const publicKeyInfo = AsnParser.parse(key.data, core.asn1.PublicKeyInfo);
return publicKeyInfo.publicKey;
}
default:
@ -130,25 +128,25 @@ export class EcCrypto {
case "jwk": {
const jwk = keyData as JsonWebKey;
if (jwk.d) {
const asnKey = JsonParser.fromJSON(keyData, { targetSchema: asn.EcPrivateKey });
const asnKey = JsonParser.fromJSON(keyData, { targetSchema: core.asn1.EcPrivateKey });
return this.importPrivateKey(asnKey, algorithm, extractable, keyUsages);
} else {
const asnKey = JsonParser.fromJSON(keyData, { targetSchema: asn.EcPublicKey });
const asnKey = JsonParser.fromJSON(keyData, { targetSchema: core.asn1.EcPublicKey });
return this.importPublicKey(asnKey, algorithm, extractable, keyUsages);
}
}
case "raw": {
const asnKey = new asn.EcPublicKey(keyData as ArrayBuffer);
const asnKey = new core.asn1.EcPublicKey(keyData as ArrayBuffer);
return this.importPublicKey(asnKey, algorithm, extractable, keyUsages);
}
case "spki": {
const keyInfo = AsnParser.parse(new Uint8Array(keyData as ArrayBuffer), asn.PublicKeyInfo);
const asnKey = new asn.EcPublicKey(keyInfo.publicKey);
const keyInfo = AsnParser.parse(new Uint8Array(keyData as ArrayBuffer), core.asn1.PublicKeyInfo);
const asnKey = new core.asn1.EcPublicKey(keyInfo.publicKey);
return this.importPublicKey(asnKey, algorithm, extractable, keyUsages);
}
case "pkcs8": {
const keyInfo = AsnParser.parse(new Uint8Array(keyData as ArrayBuffer), asn.PrivateKeyInfo);
const asnKey = AsnParser.parse(keyInfo.privateKey, asn.EcPrivateKey);
const keyInfo = AsnParser.parse(new Uint8Array(keyData as ArrayBuffer), core.asn1.PrivateKeyInfo);
const asnKey = AsnParser.parse(keyInfo.privateKey, core.asn1.EcPrivateKey);
return this.importPrivateKey(asnKey, algorithm, extractable, keyUsages);
}
default:
@ -156,10 +154,10 @@ export class EcCrypto {
}
}
protected static async importPrivateKey(asnKey: asn.EcPrivateKey, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]) {
const keyInfo = new asn.PrivateKeyInfo();
protected static async importPrivateKey(asnKey: core.asn1.EcPrivateKey, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]) {
const keyInfo = new core.asn1.PrivateKeyInfo();
keyInfo.privateKeyAlgorithm.algorithm = "1.2.840.10045.2.1";
keyInfo.privateKeyAlgorithm.parameters = AsnSerializer.serialize(new ObjectIdentifier(getOidByNamedCurve(algorithm.namedCurve)));
keyInfo.privateKeyAlgorithm.parameters = AsnSerializer.serialize(new core.asn1.ObjectIdentifier(getOidByNamedCurve(algorithm.namedCurve)));
keyInfo.privateKey = AsnSerializer.serialize(asnKey);
const key = new EcPrivateKey();
@ -172,10 +170,10 @@ export class EcCrypto {
return key;
}
protected static async importPublicKey(asnKey: asn.EcPublicKey, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]) {
const keyInfo = new asn.PublicKeyInfo();
protected static async importPublicKey(asnKey: core.asn1.EcPublicKey, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]) {
const keyInfo = new core.asn1.PublicKeyInfo();
keyInfo.publicKeyAlgorithm.algorithm = "1.2.840.10045.2.1";
keyInfo.publicKeyAlgorithm.parameters = AsnSerializer.serialize(new ObjectIdentifier(getOidByNamedCurve(algorithm.namedCurve)));
keyInfo.publicKeyAlgorithm.parameters = AsnSerializer.serialize(new core.asn1.ObjectIdentifier(getOidByNamedCurve(algorithm.namedCurve)));
keyInfo.publicKey = asnKey.value;
const key = new EcPublicKey();

View File

@ -1,8 +1,6 @@
import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema";
import { IJsonConvertible, JsonParser, JsonSerializer } from "@peculiar/json-schema";
import * as core from "webcrypto-core";
import * as asn from "../../asn";
import { ObjectIdentifier } from "../../asn";
import { AsymmetricKey } from "../../keys";
import { getOidByNamedCurve } from "./helper";
@ -11,8 +9,8 @@ export class EcPrivateKey extends AsymmetricKey implements IJsonConvertible {
public algorithm!: EcKeyAlgorithm;
public getKey() {
const keyInfo = AsnParser.parse(this.data, asn.PrivateKeyInfo);
return AsnParser.parse(keyInfo.privateKey, asn.EcPrivateKey);
const keyInfo = AsnParser.parse(this.data, core.asn1.PrivateKeyInfo);
return AsnParser.parse(keyInfo.privateKey, core.asn1.EcPrivateKey);
}
public toJSON() {
@ -33,12 +31,12 @@ export class EcPrivateKey extends AsymmetricKey implements IJsonConvertible {
throw new core.OperationError(`Cannot get named curve from JWK. Property 'crv' is required`);
}
const keyInfo = new asn.PrivateKeyInfo();
const keyInfo = new core.asn1.PrivateKeyInfo();
keyInfo.privateKeyAlgorithm.algorithm = "1.2.840.10045.2.1";
keyInfo.privateKeyAlgorithm.parameters = AsnSerializer.serialize(
new ObjectIdentifier(getOidByNamedCurve(json.crv)),
new core.asn1.ObjectIdentifier(getOidByNamedCurve(json.crv)),
);
const key = JsonParser.fromJSON(json, { targetSchema: asn.EcPrivateKey });
const key = JsonParser.fromJSON(json, { targetSchema: core.asn1.EcPrivateKey });
keyInfo.privateKey = AsnSerializer.serialize(key);
this.data = Buffer.from(AsnSerializer.serialize(keyInfo));

View File

@ -1,8 +1,6 @@
import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema";
import { IJsonConvertible, JsonParser, JsonSerializer } from "@peculiar/json-schema";
import * as core from "webcrypto-core";
import * as asn from "../../asn";
import { ObjectIdentifier } from "../../asn";
import { AsymmetricKey } from "../../keys/asymmetric";
import { getOidByNamedCurve } from "./helper";
@ -12,8 +10,8 @@ export class EcPublicKey extends AsymmetricKey implements IJsonConvertible {
public algorithm!: EcKeyAlgorithm;
public getKey() {
const keyInfo = AsnParser.parse(this.data, asn.PublicKeyInfo);
return new asn.EcPublicKey(keyInfo.publicKey);
const keyInfo = AsnParser.parse(this.data, core.asn1.PublicKeyInfo);
return new core.asn1.EcPublicKey(keyInfo.publicKey);
}
public toJSON() {
@ -34,12 +32,12 @@ export class EcPublicKey extends AsymmetricKey implements IJsonConvertible {
throw new core.OperationError(`Cannot get named curve from JWK. Property 'crv' is required`);
}
const key = JsonParser.fromJSON(json, { targetSchema: asn.EcPublicKey });
const key = JsonParser.fromJSON(json, { targetSchema: core.asn1.EcPublicKey });
const keyInfo = new asn.PublicKeyInfo();
const keyInfo = new core.asn1.PublicKeyInfo();
keyInfo.publicKeyAlgorithm.algorithm = "1.2.840.10045.2.1";
keyInfo.publicKeyAlgorithm.parameters = AsnSerializer.serialize(
new ObjectIdentifier(getOidByNamedCurve(json.crv)),
new core.asn1.ObjectIdentifier(getOidByNamedCurve(json.crv)),
);
keyInfo.publicKey = AsnSerializer.toASN(key).valueHex;

View File

@ -2,7 +2,6 @@ import crypto from "crypto";
import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema";
import { JsonParser, JsonSerializer } from "@peculiar/json-schema";
import * as core from "webcrypto-core";
import * as asn from "../../asn";
import { CryptoKey } from "../../keys";
import { RsaPrivateKey } from "./private_key";
import { RsaPublicKey } from "./public_key";
@ -77,21 +76,21 @@ export class RsaCrypto {
case "jwk": {
const jwk = keyData as JsonWebKey;
if (jwk.d) {
const asnKey = JsonParser.fromJSON(keyData, { targetSchema: asn.RsaPrivateKey });
const asnKey = JsonParser.fromJSON(keyData, { targetSchema: core.asn1.RsaPrivateKey });
return this.importPrivateKey(asnKey, algorithm, extractable, keyUsages);
} else {
const asnKey = JsonParser.fromJSON(keyData, { targetSchema: asn.RsaPublicKey });
const asnKey = JsonParser.fromJSON(keyData, { targetSchema: core.asn1.RsaPublicKey });
return this.importPublicKey(asnKey, algorithm, extractable, keyUsages);
}
}
case "spki": {
const keyInfo = AsnParser.parse(new Uint8Array(keyData as ArrayBuffer), asn.PublicKeyInfo);
const asnKey = AsnParser.parse(keyInfo.publicKey, asn.RsaPublicKey);
const keyInfo = AsnParser.parse(new Uint8Array(keyData as ArrayBuffer), core.asn1.PublicKeyInfo);
const asnKey = AsnParser.parse(keyInfo.publicKey, core.asn1.RsaPublicKey);
return this.importPublicKey(asnKey, algorithm, extractable, keyUsages);
}
case "pkcs8": {
const keyInfo = AsnParser.parse(new Uint8Array(keyData as ArrayBuffer), asn.PrivateKeyInfo);
const asnKey = AsnParser.parse(keyInfo.privateKey, asn.RsaPrivateKey);
const keyInfo = AsnParser.parse(new Uint8Array(keyData as ArrayBuffer), core.asn1.PrivateKeyInfo);
const asnKey = AsnParser.parse(keyInfo.privateKey, core.asn1.RsaPrivateKey);
return this.importPrivateKey(asnKey, algorithm, extractable, keyUsages);
}
default:
@ -137,8 +136,8 @@ export class RsaCrypto {
}
}
protected static importPrivateKey(asnKey: asn.RsaPrivateKey, algorithm: RsaHashedImportParams, extractable: boolean, keyUsages: KeyUsage[]) {
const keyInfo = new asn.PrivateKeyInfo();
protected static importPrivateKey(asnKey: core.asn1.RsaPrivateKey, algorithm: RsaHashedImportParams, extractable: boolean, keyUsages: KeyUsage[]) {
const keyInfo = new core.asn1.PrivateKeyInfo();
keyInfo.privateKeyAlgorithm.algorithm = "1.2.840.113549.1.1.1";
keyInfo.privateKeyAlgorithm.parameters = null;
keyInfo.privateKey = AsnSerializer.serialize(asnKey);
@ -155,8 +154,8 @@ export class RsaCrypto {
return key;
}
protected static importPublicKey(asnKey: asn.RsaPublicKey, algorithm: RsaHashedImportParams, extractable: boolean, keyUsages: KeyUsage[]) {
const keyInfo = new asn.PublicKeyInfo();
protected static importPublicKey(asnKey: core.asn1.RsaPublicKey, algorithm: RsaHashedImportParams, extractable: boolean, keyUsages: KeyUsage[]) {
const keyInfo = new core.asn1.PublicKeyInfo();
keyInfo.publicKeyAlgorithm.algorithm = "1.2.840.113549.1.1.1";
keyInfo.publicKeyAlgorithm.parameters = null;
keyInfo.publicKey = AsnSerializer.serialize(asnKey);

View File

@ -1,6 +1,6 @@
import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema";
import { JsonParser, JsonSerializer } from "@peculiar/json-schema";
import * as asn from "../../asn";
import * as core from "webcrypto-core";
import { AsymmetricKey } from "../../keys";
import { getJwkAlgorithm } from "./helper";
@ -9,8 +9,8 @@ export class RsaPrivateKey extends AsymmetricKey {
public algorithm!: RsaHashedKeyAlgorithm;
public getKey() {
const keyInfo = AsnParser.parse(this.data, asn.PrivateKeyInfo);
return AsnParser.parse(keyInfo.privateKey, asn.RsaPrivateKey);
const keyInfo = AsnParser.parse(this.data, core.asn1.PrivateKeyInfo);
return AsnParser.parse(keyInfo.privateKey, core.asn1.RsaPrivateKey);
}
public toJSON() {
@ -27,9 +27,9 @@ export class RsaPrivateKey extends AsymmetricKey {
}
public fromJSON(json: JsonWebKey) {
const key = JsonParser.fromJSON(json, { targetSchema: asn.RsaPrivateKey });
const key = JsonParser.fromJSON(json, { targetSchema: core.asn1.RsaPrivateKey });
const keyInfo = new asn.PrivateKeyInfo();
const keyInfo = new core.asn1.PrivateKeyInfo();
keyInfo.privateKeyAlgorithm.algorithm = "1.2.840.113549.1.1.1";
keyInfo.privateKeyAlgorithm.parameters = null;
keyInfo.privateKey = AsnSerializer.serialize(key);

View File

@ -1,6 +1,6 @@
import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema";
import { JsonParser, JsonSerializer } from "@peculiar/json-schema";
import * as asn from "../../asn";
import * as core from "webcrypto-core";
import { AsymmetricKey } from "../../keys/asymmetric";
import { getJwkAlgorithm } from "./helper";
@ -9,8 +9,8 @@ export class RsaPublicKey extends AsymmetricKey {
public algorithm!: RsaHashedKeyAlgorithm;
public getKey() {
const keyInfo = AsnParser.parse(this.data, asn.PublicKeyInfo);
return AsnParser.parse(keyInfo.publicKey, asn.RsaPublicKey);
const keyInfo = AsnParser.parse(this.data, core.asn1.PublicKeyInfo);
return AsnParser.parse(keyInfo.publicKey, core.asn1.RsaPublicKey);
}
public toJSON() {
@ -27,9 +27,9 @@ export class RsaPublicKey extends AsymmetricKey {
}
public fromJSON(json: JsonWebKey) {
const key = JsonParser.fromJSON(json, { targetSchema: asn.RsaPublicKey });
const key = JsonParser.fromJSON(json, { targetSchema: core.asn1.RsaPublicKey });
const keyInfo = new asn.PublicKeyInfo();
const keyInfo = new core.asn1.PublicKeyInfo();
keyInfo.publicKeyAlgorithm.algorithm = "1.2.840.113549.1.1.1";
keyInfo.publicKeyAlgorithm.parameters = null;
keyInfo.publicKey = AsnSerializer.serialize(key);

View File

@ -1,114 +0,0 @@
import assert from "assert";
import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema";
import { JsonParser, JsonSerializer } from "@peculiar/json-schema";
import * as asn from "../src/asn";
context("ASN", () => {
context("RSA", () => {
context("PrivateKey", () => {
const bytes = Buffer.from("308204bd020100300d06092a864886f70d0101010500048204a7308204a30201000282010100faa3f76e5daf5dc288a54b7a99d7c7a9437581a184d80bb1aaf54cdfe245b28f52edb4db4888199e78ce993407bfd93c8102231b173eca09d44bb127c152b2e7f3a806852ed1dc323a1a33a5fecc0217ea98ddeb7068c14ffbbbd14a7904b3657a663ab76d2d88b10db77bc1b22e8881e58665508af0c31da225d08f3b07ad05bd8cf4d25943bffd3bb57d4266582276089e126db030d8ef04e0c30eeb65c325558d98bfc43b2b0c52212f3294d3ad7a91fa2ec2e838b2e73a4db616ec6aad5592dfc046f7e3589741fa0f4662fcf4ffca767611475f05272b3ddbd09b757b56f0293089d39e2cdd35722cd69ea00b3181e6e7c5e531f6608db3da31ce82afad02030100010282010025698d3901adf8125e204244822b45e7dba4721da07d393da375ab2c6e139644338e3ce5508dd43925f23cc719f306a3b3e414466a715a6a1e30d0384d70a138e3536ce9bb63e2f8f2584fe652c2b3fb4aeed78d59c1a13d65a792e5896becb5549066ea53572d24b495f358a5d6b154a664a9c1dc8374b47b2c26d6026b3265b1d6e4448bd2253ce467ae99017c53af1fb085cdd5c8dc3cc66941beaa480295e907a936776f49e5e619d5e2e89e5a1bf220121c965b08b658d669464a4d0eb414efe11c8fa20987fae0758542ec69a9d335b01a78b8770b499272105629b4e81f04065644928f0b01bfb0294fbeb0e0e4e3ad6129d356fce820d35171126b1702818100fe042d914643ad84d8e5a0d0c3c7dc9b35ac60d96ef9305e74ead8419a1937c3a4d5b6b2d589f818ab0cfa4f6ee12fbeb85f7c117ba4eb489b31f0eecac4f8368b52b3339043a3160fa3535e1e45634947b582438149b062b73029bd2279793154153da0e120c48fe71c466783e6537ea9157d776bedd272e08fe4e961fe14ff02818100fc990a2846cf6c0f38ad798855a81f2386795425523f99a8660968be450564d97d62b58533bb9e65c36d56d28480b39bbbfaf7ddfdb8b08aa080740038b1786e659dfb342cdf197bcb8c40af1719814c734cec50b3e915cf927b6eb8e880d4073ab2d6c1e106c78e5add9042476f78edfb76d2d7ef5e1ae4c33f51c558691f5302818100b4a329f86e5c40700182427b534eb4add75c6f3f10b0ba59e191041a9ac82624c5fa88c2e2220c41169ad3025bda5d86a63c98d121f964ac2c593679c9ce8aa8d7290770babdaea348999ff6855658c5caede3e5b7723cb1e68da490f08c2bc80d8051642fd48a93bf09177413935e7aeb28f22153aa3b0720749397f7eca4e702818067661215589f11c1cd569d98245014a70b25e13f01c30d1834e4871ed3cc18733af34c10c1937c8c7589ed6f7153e9b1c72a3d8a7e90ba9b9485e07632bedae87dea44692031171268c8f9b572843b3c5b3a52c5da4f80611eba2e21bcf2f7581a3c18d2f6553b1cd7af389d18f6d58ebd4fef90fae80fa433145959aa0e260702818045ef370e79be4352cae716a92244f37f0b4a5133442b49de4a8bc5342d40a00eed284dcb5061d6dcde01baa12fde1ee965f66acabf58bd08d2f78c8f5f00a9156242ea971940611c8f9892335e48e211d2667aa0c5186af712cbab48802f2fc37488316e72d8dfd28a9e311e962fba79324e14d61a61d4afc4646da76dc650ae", "hex");
const json = {
d: "JWmNOQGt-BJeIEJEgitF59ukch2gfTk9o3WrLG4TlkQzjjzlUI3UOSXyPMcZ8wajs-QURmpxWmoeMNA4TXChOONTbOm7Y-L48lhP5lLCs_tK7teNWcGhPWWnkuWJa-y1VJBm6lNXLSS0lfNYpdaxVKZkqcHcg3S0eywm1gJrMmWx1uREi9IlPORnrpkBfFOvH7CFzdXI3DzGaUG-qkgClekHqTZ3b0nl5hnV4uieWhvyIBIcllsItljWaUZKTQ60FO_hHI-iCYf64HWFQuxpqdM1sBp4uHcLSZJyEFYptOgfBAZWRJKPCwG_sClPvrDg5OOtYSnTVvzoINNRcRJrFw",
dp: "tKMp-G5cQHABgkJ7U060rddcbz8QsLpZ4ZEEGprIJiTF-ojC4iIMQRaa0wJb2l2GpjyY0SH5ZKwsWTZ5yc6KqNcpB3C6va6jSJmf9oVWWMXK7ePlt3I8seaNpJDwjCvIDYBRZC_UipO_CRd0E5Neeuso8iFTqjsHIHSTl_fspOc",
dq: "Z2YSFVifEcHNVp2YJFAUpwsl4T8Bww0YNOSHHtPMGHM680wQwZN8jHWJ7W9xU-mxxyo9in6QupuUheB2Mr7a6H3qRGkgMRcSaMj5tXKEOzxbOlLF2k-AYR66LiG88vdYGjwY0vZVOxzXrzidGPbVjr1P75D66A-kMxRZWaoOJgc",
e: "AQAB",
n: "-qP3bl2vXcKIpUt6mdfHqUN1gaGE2AuxqvVM3-JFso9S7bTbSIgZnnjOmTQHv9k8gQIjGxc-ygnUS7EnwVKy5_OoBoUu0dwyOhozpf7MAhfqmN3rcGjBT_u70Up5BLNlemY6t20tiLENt3vBsi6IgeWGZVCK8MMdoiXQjzsHrQW9jPTSWUO__Tu1fUJmWCJ2CJ4SbbAw2O8E4MMO62XDJVWNmL_EOysMUiEvMpTTrXqR-i7C6Diy5zpNthbsaq1Vkt_ARvfjWJdB-g9GYvz0_8p2dhFHXwUnKz3b0Jt1e1bwKTCJ054s3TVyLNaeoAsxgebnxeUx9mCNs9oxzoKvrQ",
p: "_gQtkUZDrYTY5aDQw8fcmzWsYNlu-TBedOrYQZoZN8Ok1bay1Yn4GKsM-k9u4S--uF98EXuk60ibMfDuysT4NotSszOQQ6MWD6NTXh5FY0lHtYJDgUmwYrcwKb0ieXkxVBU9oOEgxI_nHEZng-ZTfqkVfXdr7dJy4I_k6WH-FP8",
q: "_JkKKEbPbA84rXmIVagfI4Z5VCVSP5moZglovkUFZNl9YrWFM7ueZcNtVtKEgLObu_r33f24sIqggHQAOLF4bmWd-zQs3xl7y4xArxcZgUxzTOxQs-kVz5J7brjogNQHOrLWweEGx45a3ZBCR2947ft20tfvXhrkwz9RxVhpH1M",
qi: "Re83Dnm-Q1LK5xapIkTzfwtKUTNEK0neSovFNC1AoA7tKE3LUGHW3N4BuqEv3h7pZfZqyr9YvQjS94yPXwCpFWJC6pcZQGEcj5iSM15I4hHSZnqgxRhq9xLLq0iALy_DdIgxbnLY39KKnjEeli-6eTJOFNYaYdSvxGRtp23GUK4",
};
it("parse", () => {
const keyInfo = AsnParser.parse(bytes, asn.PrivateKeyInfo);
const key = AsnParser.parse(keyInfo.privateKey, asn.RsaPrivateKey);
const jsonKey = JsonSerializer.toJSON(key);
assert.deepEqual(jsonKey, json);
});
it("serialize", () => {
const key = JsonParser.fromJSON(json, { targetSchema: asn.RsaPrivateKey });
const keyInfo = new asn.PrivateKeyInfo();
keyInfo.privateKeyAlgorithm.algorithm = "1.2.840.113549.1.1.1";
keyInfo.privateKeyAlgorithm.parameters = null;
keyInfo.privateKey = AsnSerializer.serialize(key);
const asnKeyInfo = Buffer.from(AsnSerializer.serialize(keyInfo));
assert.equal(asnKeyInfo.equals(bytes), true);
});
});
context("PublicKey", () => {
const bytes = Buffer.from("30820122300d06092a864886f70d01010105000382010f003082010a0282010100faa3f76e5daf5dc288a54b7a99d7c7a9437581a184d80bb1aaf54cdfe245b28f52edb4db4888199e78ce993407bfd93c8102231b173eca09d44bb127c152b2e7f3a806852ed1dc323a1a33a5fecc0217ea98ddeb7068c14ffbbbd14a7904b3657a663ab76d2d88b10db77bc1b22e8881e58665508af0c31da225d08f3b07ad05bd8cf4d25943bffd3bb57d4266582276089e126db030d8ef04e0c30eeb65c325558d98bfc43b2b0c52212f3294d3ad7a91fa2ec2e838b2e73a4db616ec6aad5592dfc046f7e3589741fa0f4662fcf4ffca767611475f05272b3ddbd09b757b56f0293089d39e2cdd35722cd69ea00b3181e6e7c5e531f6608db3da31ce82afad0203010001", "hex");
const json = {
n: "-qP3bl2vXcKIpUt6mdfHqUN1gaGE2AuxqvVM3-JFso9S7bTbSIgZnnjOmTQHv9k8gQIjGxc-ygnUS7EnwVKy5_OoBoUu0dwyOhozpf7MAhfqmN3rcGjBT_u70Up5BLNlemY6t20tiLENt3vBsi6IgeWGZVCK8MMdoiXQjzsHrQW9jPTSWUO__Tu1fUJmWCJ2CJ4SbbAw2O8E4MMO62XDJVWNmL_EOysMUiEvMpTTrXqR-i7C6Diy5zpNthbsaq1Vkt_ARvfjWJdB-g9GYvz0_8p2dhFHXwUnKz3b0Jt1e1bwKTCJ054s3TVyLNaeoAsxgebnxeUx9mCNs9oxzoKvrQ",
e: "AQAB",
};
it("parse", () => {
const keyInfo = AsnParser.parse(bytes, asn.PublicKeyInfo);
const key = AsnParser.parse(keyInfo.publicKey, asn.RsaPublicKey);
const jsonKey = JsonSerializer.toJSON(key);
assert.deepEqual(jsonKey, json);
});
it("serialize", () => {
const key = JsonParser.fromJSON(json, { targetSchema: asn.RsaPublicKey });
const keyInfo = new asn.PublicKeyInfo();
keyInfo.publicKeyAlgorithm.algorithm = "1.2.840.113549.1.1.1";
keyInfo.publicKeyAlgorithm.parameters = null;
keyInfo.publicKey = AsnSerializer.serialize(key);
const asnKeyInfo = Buffer.from(AsnSerializer.serialize(keyInfo));
assert.equal(asnKeyInfo.equals(bytes), true);
});
});
});
context("EC", () => {
context("PrivateKey", () => {
const bytes = Buffer.from("308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b0201010420db0964fc2a963e9a2aef561f57db3556fa87e83ceb2e5f6dc84b00c18aa873e3a144034200043266c1386af7a0993b169393df1f7c4016e27fd48642e8d512c775b31c8f06722baef1310974a6c63aff2ef8832fba27f021f5ae2f2c6c2d56fde5be5ade78f5", "hex");
const json = {
d: "2wlk_CqWPpoq71YfV9s1VvqH6DzrLl9tyEsAwYqoc-M",
x: "MmbBOGr3oJk7FpOT3x98QBbif9SGQujVEsd1sxyPBnI",
y: "K67xMQl0psY6_y74gy-6J_Ah9a4vLGwtVv3lvlreePU",
};
it("parse", () => {
const keyInfo = AsnParser.parse(bytes, asn.PrivateKeyInfo);
const key = AsnParser.parse(keyInfo.privateKey, asn.EcPrivateKey);
const jsonKey = JsonSerializer.toJSON(key);
assert.deepEqual(jsonKey, json);
});
it("serialize", () => {
const keyInfo = new asn.PrivateKeyInfo();
keyInfo.privateKeyAlgorithm.algorithm = "1.2.840.10045.2.1";
keyInfo.privateKeyAlgorithm.parameters = AsnSerializer.serialize(
new asn.ObjectIdentifier("1.2.840.10045.3.1.7"),
);
const key = JsonParser.fromJSON(json, { targetSchema: asn.EcPrivateKey });
keyInfo.privateKey = AsnSerializer.serialize(key);
const asnKeyInfo = Buffer.from(AsnSerializer.serialize(keyInfo));
assert.equal(asnKeyInfo.equals(bytes), true);
});
});
});
});