Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

P256 support #34

Merged
merged 4 commits into from
Oct 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .example.env
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ SECP256K1_KEY=/secp256k1
SECP256K1_SIGN_ETHEREUM_TRANSACTION=/secp256k1/sign/ethereum-tx
SECP256K1_SIGN_LACCHAIN_TRANSACTION=/secp256k1/sign/lacchain-tx
ED25519_CREATE_KEY=/ed25519
P256_CREATE_KEY=/p256

# Did Registry
CHAIN_ID = 0x9e55c
Expand Down
1 change: 1 addition & 0 deletions .example.env.dev
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ SECP256K1_KEY=/secp256k1
SECP256K1_SIGN_ETHEREUM_TRANSACTION=/secp256k1/sign/ethereum-tx
SECP256K1_SIGN_LACCHAIN_TRANSACTION=/secp256k1/sign/lacchain-tx
ED25519_CREATE_KEY=/ed25519
P256_CREATE_KEY=/p256


# Did Registry
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Changelog

## 0.0.3

* Add support to associate a P-256 JWK to a DID
## 0.0.1

### Additions and Improvements
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "lacchain-identity",
"version": "0.0.2",
"version": "0.0.6",
"description": "Rest api for lacchain identity manager",
"main": "dist/src/index.js",
"types": "dist/src/index.d.ts",
Expand Down Expand Up @@ -85,7 +85,7 @@
"helmet": "^5.0.2",
"json-canonicalize": "^1.0.6",
"jsonwebtoken": "^9.0.0",
"lacchain-key-manager": "^0.0.2",
"lacchain-key-manager": "^0.0.6",
"morgan": "^1.10.0",
"multer": "^1.4.4",
"nodemailer": "^6.7.3",
Expand Down
3 changes: 2 additions & 1 deletion src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,5 +208,6 @@ export const {
LACCHAIN_IDENTITY_IS_DEPENDENT_SERVICE,
SECP256K1_SIGN_ETHEREUM_TRANSACTION,
SECP256K1_SIGN_LACCHAIN_TRANSACTION,
ED25519_CREATE_KEY
ED25519_CREATE_KEY,
P256_CREATE_KEY
} = process.env;
8 changes: 6 additions & 2 deletions src/constants/errorMessages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export enum ErrorsMessages {
INVALID_EXPIRATION_DAYS = 'Valid days must be greater than zero',
INVALID_JWK_TYPE = 'Invalid Jwk type',
// eslint-disable-next-line max-len
UNSUPPORTED_JWK_CREATION_FOR_TYPE = 'The type of jwk for creation is not supported yet, valid type: "secp256k1"',
UNSUPPORTED_JWK_CREATION_FOR_TYPE = 'The type of jwk for creation is not supported yet, valid type: "secp256k1" or "secp256r1"',
INVALID_VM_RELATION_TYPE = 'Invalid verification method relation type',
UNSUPPORTED_ATTRIBUTE_ENCODING_METHOD = 'Unsupported attribute encoding',
INVALID_DELEGATE_TYPE = 'Invalid delegate type',
Expand All @@ -46,7 +46,11 @@ export enum ErrorsMessages {
UNEXPECTED_RESPONSE_IN_SUCCESSFUL_TRANSACTION_ERROR = 'Transaction was successfully completed but received an unexpected response',
UNSUPPORTED_CHAIN_ID_IN_DID = 'Unsupported chainId was found in DID',
UNSUPPORTED_DID_TYPE = 'Unsupported DID type',
UNSUPPORTED_DID_VERSION = 'Unsupported DID version'
UNSUPPORTED_DID_VERSION = 'Unsupported DID version',
// eslint-disable-next-line max-len
PUBLIC_KEY_COMPRESSED_FORMAT_ERROR = 'Unexpected public key format, expected compressed format',
// eslint-disable-next-line max-len
PUBLIC_KEY_UNCOMPRESSED_FORMAT_ERROR = 'Unexpected public key format, expected uncompressed format'
}

export const Errors = {
Expand Down
2 changes: 1 addition & 1 deletion src/dto/did-lac/attributeDTO.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export class NewAttributeDTO {

export class NewJwkAttributeDTO extends NewAttributeDTO {
@IsString()
jwkType!: 'secp256k1';
jwkType!: 'secp256k1' | 'secp256r1';
}

export class RevokeAttributeDTO {
Expand Down
2 changes: 1 addition & 1 deletion src/interfaces/did-lacchain/did-lacchain.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export interface INewAttribute {
}

export interface INewJwkAttribute extends INewAttribute {
jwkType: 'secp256k1';
jwkType: 'secp256k1' | 'secp256r1';
}

export interface IAccountIdAttribute {
Expand Down
2 changes: 2 additions & 0 deletions src/interfaces/key/key.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@ export interface IECKey {
address: string;
publicKey: string;
type: string;
x?: string;
y?: string;
}
91 changes: 71 additions & 20 deletions src/services/did-lac/did.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,31 +159,82 @@ export abstract class DidService implements DidLacService {
}
async addNewJwkAttribute(attribute: INewJwkAttribute): Promise<any> {
if (attribute.jwkType == 'secp256k1') {
const key = await this.keyManagerService.createSecp256k1Key();
const x = Buffer.from(key.publicKey.replace('0x', ''), 'hex').toString(
'base64url'
);
const ecJwk: EcJwk = {
kty: 'EC',
x,
crv: 'secp256k1'
};
const ecJwkAttribute: IJwkEcAttribute = {
did: attribute.did,
ecJwk,
validDays: attribute.validDays,
relation: attribute.relation
};
const r: INewJwkAttributeCreationResponse = {
...(await this.addEcJwkAttribute(ecJwkAttribute)),
jwk: ecJwk
};
return r;
return this.addNewSecp256k1JwkAttribute(attribute);
} else if (attribute.jwkType == 'secp256r1') {
return this.addNewSecp256r1JwkAttribute(attribute);
}
const message = ErrorsMessages.UNSUPPORTED_JWK_CREATION_FOR_TYPE;
this.log.info(message);
throw new BadRequestError(message);
}

async addNewSecp256k1JwkAttribute(attribute: INewJwkAttribute): Promise<any> {
const key = await this.keyManagerService.createSecp256k1Key();
// invariant verification
const pubKey = key.publicKey.replace('0x', '');
if (pubKey.length !== 66 || !pubKey.startsWith('02')) {
throw new BadRequestError(
ErrorsMessages.PUBLIC_KEY_COMPRESSED_FORMAT_ERROR
);
}
const x = Buffer.from(key.publicKey.replace('0x02', ''), 'hex').toString(
'base64url'
);
const ecJwk: EcJwk = {
kty: 'EC',
x,
crv: 'secp256k1'
};
const ecJwkAttribute: IJwkEcAttribute = {
did: attribute.did,
ecJwk,
validDays: attribute.validDays,
relation: attribute.relation
};
const r: INewJwkAttributeCreationResponse = {
...(await this.addEcJwkAttribute(ecJwkAttribute)),
jwk: ecJwk
};
return r;
}

async addNewSecp256r1JwkAttribute(attribute: INewJwkAttribute): Promise<any> {
const key = await this.keyManagerService.createP256Key();
// invariant verification
const pubKey = key.publicKey.replace('0x', '');
if (pubKey.length !== 130 || !pubKey.startsWith('04')) {
throw new BadRequestError(
ErrorsMessages.PUBLIC_KEY_UNCOMPRESSED_FORMAT_ERROR
);
}
const pubKeyNoPrefix = key.publicKey.replace('04', '');
const x = Buffer.from(pubKeyNoPrefix.substring(0, 64), 'hex').toString(
'base64url'
);
const y = Buffer.from(pubKeyNoPrefix.substring(64, 128), 'hex').toString(
'base64url'
);

const ecJwk: EcJwk = {
kty: 'EC',
x,
y,
crv: 'P-256'
};
console.log(ecJwk);
const ecJwkAttribute: IJwkEcAttribute = {
did: attribute.did,
ecJwk,
validDays: attribute.validDays,
relation: attribute.relation
};
const r: INewJwkAttributeCreationResponse = {
...(await this.addEcJwkAttribute(ecJwkAttribute)),
jwk: ecJwk
};
return r;
}

async addRsaJwkAttribute(jwkRsaAttribute: IJwkRsaAttribute): Promise<any> {
// TODO: validate RSA params
const { kty } = jwkRsaAttribute.rsaJwk;
Expand Down
31 changes: 30 additions & 1 deletion src/services/external/key-manager.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import {
SECP256K1_SIGN_ETHEREUM_TRANSACTION,
SECP256K1_SIGN_LACCHAIN_TRANSACTION,
log4TSProvider,
ED25519_CREATE_KEY
ED25519_CREATE_KEY,
P256_CREATE_KEY
} from '../../config';
import {
IEthereumTransaction,
Expand All @@ -24,6 +25,7 @@ import { IECKey } from 'src/interfaces/key/key.interface';
export class KeyManagerService {
public createSecp256k1Key: () => Promise<IECKey>;
public createEd25519Key: () => Promise<IECKey>;
public createP256Key: () => Promise<IECKey>;
public signEthereumTransaction: (
ethereumTransaction: IEthereumTransaction
) => Promise<ISignedTransaction>;
Expand All @@ -35,6 +37,7 @@ export class KeyManagerService {
// eslint-disable-next-line max-len
private secp256k1SignLacchainTransactionService: Secp256k1SignLacchainTransactionService | null;
private generic25519Service: ECService | null;
private p256KeyService: ECService | null;
log = log4TSProvider.getLogger('KeyManagerService');
constructor() {
if (LACCHAIN_IDENTITY_IS_DEPENDENT_SERVICE !== 'true') {
Expand All @@ -56,6 +59,10 @@ export class KeyManagerService {
this.createEd25519Key = this.createEd25519KeyByLib;
const SS = require('lacchain-key-manager').Generic25519DbService;
this.generic25519Service = new SS('ed25519');

this.createP256Key = this.createP256KeyByLib;
const TT = require('lacchain-key-manager').P256DbService;
this.p256KeyService = new TT();
} else {
this.log.info('Configuring key-manager external service connection');
this.secp256k1Service = null;
Expand All @@ -71,6 +78,9 @@ export class KeyManagerService {

this.generic25519Service = null;
this.createEd25519Key = this.createEd25519KeyByExternalService;

this.p256KeyService = null;
this.createP256Key = this.createP256KeyByExternalService;
}
}
async createSecp256k1KeyByLib(): Promise<IECKey> {
Expand Down Expand Up @@ -110,6 +120,25 @@ export class KeyManagerService {
return (await result.json()) as IECKey;
}

async createP256KeyByLib(): Promise<IECKey> {
return (await this.p256KeyService?.createKey()) as IECKey;
}

async createP256KeyByExternalService(): Promise<IECKey> {
const result = await fetch(`${KEY_MANAGER_BASE_URL}${P256_CREATE_KEY}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
});
console.log('status', result.status);
if (result.status !== 200) {
console.log(await result.text());
throw new InternalServerError(ErrorsMessages.CREATE_KEY_ERROR);
}
return (await result.json()) as IECKey;
}

async signEthereumTransactionByLib(
ethereumTransaction: IEthereumTransaction
): Promise<ISignedTransaction> {
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5402,10 +5402,10 @@ koa@^2.8.2:
type-is "^1.6.16"
vary "^1.1.2"

lacchain-key-manager@^0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/lacchain-key-manager/-/lacchain-key-manager-0.0.2.tgz#e9996ad66bdbf52e4db3148390a09dff630413b7"
integrity sha512-8qDeQUYHgZylcPQDkKc3N6eprVUlp0vCH+4GsH+iznZ6HlWhhdghMgEgYwSq1jlmM9L/jBos+m7m1iWBDWoQbg==
lacchain-key-manager@^0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/lacchain-key-manager/-/lacchain-key-manager-0.0.6.tgz#2d4c3bd175ab11332a7f4657d70438ee47bf7f18"
integrity sha512-RRuazKwiLniOuGE/PmriZqjXbOjBYIe9a1vxCCHeJGnVs6mVp3dD9MnDArszUd+xiJLL4L9CLa0hzTOYZjXOhA==
dependencies:
"@lacchain/gas-model-provider" "^1.0.1"
DIDComm-js "git+https://github.com/decentralized-identity/DIDComm-js.git"
Expand Down
Loading