Skip to content

Commit

Permalink
fix(ecc): Add SpecifiedECDomain schema from RFC3279
Browse files Browse the repository at this point in the history
  • Loading branch information
microshine committed Sep 16, 2024
1 parent 240a90c commit 63ce7a4
Show file tree
Hide file tree
Showing 4 changed files with 173 additions and 14 deletions.
11 changes: 9 additions & 2 deletions packages/ecc/src/ec_parameters.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { AsnType, AsnTypeTypes, AsnProp, AsnPropTypes } from "@peculiar/asn1-schema";
import { SpecifiedECDomain } from "./rfc3279";

/**
* ```
* ECParameters ::= CHOICE {
* namedCurve OBJECT IDENTIFIER
* -- implicitCurve NULL
* -- specifiedCurve SpecifiedECDomain
* implicitCurve NULL
* specifiedCurve SpecifiedECDomain
* }
* -- implicitCurve and specifiedCurve MUST NOT be used in PKIX.
* -- Details for SpecifiedECDomain can be found in [X9.62].
Expand All @@ -19,6 +20,12 @@ export class ECParameters {
@AsnProp({ type: AsnPropTypes.ObjectIdentifier })
public namedCurve?: string;

@AsnProp({ type: AsnPropTypes.Null })
public implicitCurve?: null;

@AsnProp({ type: SpecifiedECDomain })
public specifiedCurve?: SpecifiedECDomain;

constructor(params: Partial<ECParameters> = {}) {
Object.assign(this, params);
}
Expand Down
3 changes: 2 additions & 1 deletion packages/ecc/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ export * from "./algorithms";
export * from "./ec_parameters";
export * from "./ec_private_key";
export * from "./ec_signature_value";
export * from "./object_identifiers";
export * from "./object_identifiers";
export * from "./rfc3279";
108 changes: 108 additions & 0 deletions packages/ecc/src/rfc3279.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import { AsnType, AsnTypeTypes, AsnProp, AsnPropTypes, OctetString, AsnIntegerArrayBufferConverter } from "@peculiar/asn1-schema";

/**
* ```asn1
* FieldID ::= SEQUENCE {
* fieldType OBJECT IDENTIFIER,
* parameters ANY DEFINED BY fieldType }
* ```
*/
@AsnType({ type: AsnTypeTypes.Sequence })
export class FieldID {
@AsnProp({ type: AsnPropTypes.ObjectIdentifier })
public fieldType!: string;

@AsnProp({ type: AsnPropTypes.Any })
public parameters!: ArrayBuffer;

constructor(params: Partial<FieldID> = {}) {
Object.assign(this, params);
}
}

/**
* ```asn1
* ECPoint ::= OCTET STRING
* ```
*/
export class ECPoint extends OctetString { }

/**
* ```asn1
* FieldElement ::= OCTET STRING
* ```
*/
export class FieldElement extends OctetString { }

/**
* ```asn1
* Curve ::= SEQUENCE {
* a FieldElement,
* b FieldElement,
* seed BIT STRING OPTIONAL }
* ```
*/
@AsnType({ type: AsnTypeTypes.Sequence })
export class Curve {
@AsnProp({ type: AsnPropTypes.OctetString })
public a!: ArrayBuffer;

@AsnProp({ type: AsnPropTypes.OctetString })
public b!: ArrayBuffer;

@AsnProp({ type: AsnPropTypes.BitString, optional: true })
public seed?: ArrayBuffer;

constructor(params: Partial<Curve> = {}) {
Object.assign(this, params);
}
}

/**
* ```asn1
* ECPVer ::= INTEGER {ecpVer1(1)}
* ```
*/
export enum ECPVer {
ecpVer1 = 1,
}

/**
* ```asn1
* SpecifiedECDomain ::= SEQUENCE {
* version ECPVer, -- version is always 1
* fieldID FieldID, -- identifies the finite field over
* -- which the curve is defined
* curve Curve, -- coefficients a and b of the
* -- elliptic curve
* base ECPoint, -- specifies the base point P
* -- on the elliptic curve
* order INTEGER, -- the order n of the base point
* cofactor INTEGER OPTIONAL -- The integer h = #E(Fq)/n
* }
* ```
*/
@AsnType({ type: AsnTypeTypes.Sequence })
export class SpecifiedECDomain {
@AsnProp({ type: AsnPropTypes.Integer })
public version: ECPVer = ECPVer.ecpVer1;

@AsnProp({ type: FieldID })
public fieldID!: FieldID;

@AsnProp({ type: Curve })
public curve!: Curve;

@AsnProp({ type: ECPoint })
public base!: ECPoint;

@AsnProp({ type: AsnPropTypes.Integer, converter: AsnIntegerArrayBufferConverter })
public order!: ArrayBuffer;

@AsnProp({ type: AsnPropTypes.Integer, optional: true })
public cofactor?: ArrayBuffer;

constructor(params: Partial<SpecifiedECDomain> = {}) {
Object.assign(this, params);
}
}
65 changes: 54 additions & 11 deletions packages/ecc/test/ec_parameters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,62 @@ import { AsnConvert } from "@peculiar/asn1-schema";

context("EC parameters", () => {

const ecParamsHex = "06082a8648ce3d030107";

it("serialize", () => {
const ecParams = new ECParameters({
namedCurve: id_secp256r1,
})
const der = AsnConvert.serialize(ecParams);
assert.strictEqual(Buffer.from(der).toString("hex"), ecParamsHex);
context("Named curve", () => {

const ecParamsHex = "06082a8648ce3d030107";

it("serialize", () => {
const ecParams = new ECParameters({
namedCurve: id_secp256r1,
});
const der = AsnConvert.serialize(ecParams);
assert.strictEqual(Buffer.from(der).toString("hex"), ecParamsHex);
});

it("parse", () => {
const ecParams = AsnConvert.parse(Buffer.from(ecParamsHex, "hex"), ECParameters);
assert.strictEqual(ecParams.namedCurve, id_secp256r1);
});

});

it("parse", () => {
const ecParams = AsnConvert.parse(Buffer.from(ecParamsHex, "hex"), ECParameters);
assert.strictEqual(ecParams.namedCurve, id_secp256r1);
context("Specified curve", () => {
// Reference: https://github.com/PeculiarVentures/asn1-schema/issues/102

const ecParamsEnc = Buffer.from("MIH3AgEBMCwGByqGSM49AQECIQD_____AAAAAQAAAAAAAAAAAAAAAP_______________zBbBCD_____AAAAAQAAAAAAAAAAAAAAAP_______________AQgWsY12Ko6k-ez671VdpiGvGUdBrDMU7D2O848PifSYEsDFQDEnTYIhucEk2pmeOETnSa3gZ9-kARBBGsX0fLhLEJH-Lzm5WOkQPJ3A32BLeszoPShOUXYmMKWT-NC4v4af5uO5-tKfA-eFivOM1drMV7Oy7ZAaDe_UfUCIQD_____AAAAAP__________vOb6racXnoTzucrC_GMlUQIBAQ", "base64url");

it("parse/serialize", () => {
const ecParams = AsnConvert.parse(ecParamsEnc, ECParameters);
assert.ok(ecParams.specifiedCurve);
const specifiedCurve = ecParams.specifiedCurve;

// Check version
assert.strictEqual(specifiedCurve.version, 1);

// Check fieldID
const fieldID = specifiedCurve.fieldID;
assert.strictEqual(fieldID.fieldType, '1.2.840.10045.1.1');
assert.strictEqual(fieldID.parameters.byteLength, 35);

// Check curve
const curve = specifiedCurve.curve;
assert.strictEqual(curve.a.byteLength, 32);
assert.strictEqual(curve.b.byteLength, 32);
assert.strictEqual(curve.seed!.byteLength, 20);

// Check base
assert.strictEqual(specifiedCurve.base.byteLength, 65);

// Check order
assert.strictEqual(specifiedCurve.order.byteLength, 33);

// Check cofactor
assert.strictEqual(specifiedCurve.cofactor, 1);

// Serialize and compare
const der = AsnConvert.serialize(ecParams);
assert.strictEqual(Buffer.from(der).compare(ecParamsEnc), 0, "Encoded EC parameters are not equal");
});
});

});

0 comments on commit 63ce7a4

Please sign in to comment.