Skip to content

Commit 5c3903c

Browse files
Feat/manage x509 cert (#1492)
* added x509 cert for mdoc Signed-off-by: Rinkal Bhojani <[email protected]> * removed commented code Signed-off-by: Rinkal Bhojani <[email protected]> * removed commented code Signed-off-by: Rinkal Bhojani <[email protected]> --------- Signed-off-by: Rinkal Bhojani <[email protected]>
1 parent f351f07 commit 5c3903c

File tree

9 files changed

+113
-152
lines changed

9 files changed

+113
-152
lines changed

apps/api-gateway/src/oid4vc-issuance/dtos/oid4vc-issuer-template.dto.ts

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
import { ApiExtraModels, ApiProperty, ApiPropertyOptional, getSchemaPath, PartialType } from '@nestjs/swagger';
1515
import { Type } from 'class-transformer';
1616
import { DisplayDto } from './oid4vc-issuer.dto';
17+
import { SignerOption } from '@prisma/client';
1718

1819
export class CredentialAttributeDto {
1920
@ApiProperty({ required: false, description: 'Whether the attribute is mandatory' })
@@ -104,10 +105,6 @@ export class AppearanceDto {
104105
display: CredentialDisplayDto[];
105106
}
106107

107-
export enum SignerOption {
108-
DID = 'did',
109-
X509 = 'x509'
110-
}
111108
@ApiExtraModels(CredentialAttributeDto)
112109
export class CreateCredentialTemplateDto {
113110
@ApiProperty({ description: 'Template name' })
@@ -185,15 +182,6 @@ export class CreateCredentialTemplateDto {
185182
uri: 'https://upload.wikimedia.org/wikipedia/commons/2/2f/ABC-2021-LOGO.svg',
186183
alt_text: 'abc_logo'
187184
}
188-
},
189-
{
190-
locale: 'ar',
191-
name: 'شهادة الميلاد',
192-
description: 'سجل رسمي للولادة',
193-
logo: {
194-
uri: 'https://upload.wikimedia.org/wikipedia/commons/2/2f/ABC-2021-LOGO.svg',
195-
alt_text: 'شعار abc'
196-
}
197185
}
198186
]
199187
}

apps/oid4vc-issuance/interfaces/oid4vc-template.interfaces.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,18 @@
1-
import { Prisma } from '@prisma/client';
1+
import { Prisma, SignerOption } from '@prisma/client';
22
import { Display } from './oid4vc-issuance.interfaces';
3+
import { CredentialFormat } from '@credebl/enum/enum';
34

45
export interface CredentialAttribute {
56
mandatory?: boolean;
67
value_type: string;
78
display?: Display[];
89
}
910

10-
export enum SignerOption {
11-
DID = 'did',
12-
X509 = 'x509'
13-
}
1411
export interface CreateCredentialTemplate {
1512
name: string;
1613
description?: string;
17-
signerOption?: SignerOption;
18-
format: 'sd-jwt-vc' | 'mdoc';
14+
signerOption?: SignerOption; //SignerOption;
15+
format: CredentialFormat;
1916
issuer: string;
2017
canBeRevoked: boolean;
2118
attributes: Prisma.JsonValue;

apps/oid4vc-issuance/src/oid4vc-issuance.controller.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export class Oid4vcIssuanceController {
4747
}
4848

4949
@MessagePattern({ cmd: 'oid4vc-get-issuers-issuance' })
50-
async oidcGetIssuers(payload: { orgId: string }): Promise<object> {
50+
async oidcGetIssuers(payload: { orgId: string }): Promise<oidc_issuer[]> {
5151
const { orgId } = payload;
5252
return this.oid4vcIssuanceService.oidcIssuers(orgId);
5353
}

apps/oid4vc-issuance/src/oid4vc-issuance.repository.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import { Prisma, credential_templates, oidc_issuer, org_agents } from '@prisma/c
55
import { PrismaService } from '@credebl/prisma-service';
66
import { IssuerMetadata, IssuerUpdation, OrgAgent } from '../interfaces/oid4vc-issuance.interfaces';
77
import { ResponseMessages } from '@credebl/common/response-messages';
8+
import { x5cKeyType, x5cRecordStatus } from '@credebl/enum/enum';
9+
import { X509CertificateRecord } from '@credebl/common/interfaces/x509.interface';
810

911
@Injectable()
1012
export class Oid4vcIssuanceRepository {
@@ -111,6 +113,24 @@ export class Oid4vcIssuanceRepository {
111113
}
112114
}
113115

116+
async getAllOidcIssuersByOrg(orgId: string): Promise<oidc_issuer[]> {
117+
try {
118+
return await this.prisma.oidc_issuer.findMany({
119+
where: {
120+
orgAgent: {
121+
orgId
122+
}
123+
},
124+
orderBy: {
125+
createDateTime: 'desc'
126+
}
127+
});
128+
} catch (error) {
129+
this.logger.error(`Error in getOidcIssuerByOrg: ${error.message}`);
130+
throw error;
131+
}
132+
}
133+
114134
async getOidcIssuerDetailsById(issuerId: string): Promise<oidc_issuer> {
115135
try {
116136
return await this.prisma.oidc_issuer.findFirstOrThrow({
@@ -122,6 +142,35 @@ export class Oid4vcIssuanceRepository {
122142
}
123143
}
124144

145+
async getCurrentActiveCertificate(orgId: string, keyType: x5cKeyType): Promise<X509CertificateRecord> {
146+
try {
147+
const now = new Date();
148+
149+
const certificate = await this.prisma.x509_certificates.findFirst({
150+
where: {
151+
org_agents: {
152+
orgId
153+
},
154+
status: x5cRecordStatus.Active,
155+
keyType,
156+
validFrom: {
157+
lte: now
158+
},
159+
expiry: {
160+
gte: now
161+
}
162+
},
163+
orderBy: {
164+
createdAt: 'desc'
165+
}
166+
});
167+
return certificate;
168+
} catch (error) {
169+
this.logger.error(`Error in getCurrentActiveCertificate: ${error.message}`);
170+
throw error;
171+
}
172+
}
173+
125174
// eslint-disable-next-line @typescript-eslint/no-explicit-any
126175
async addOidcIssuerDetails(issuerMetadata: IssuerMetadata, issuerProfileJson): Promise<oidc_issuer> {
127176
try {

apps/oid4vc-issuance/src/oid4vc-issuance.service.ts

Lines changed: 41 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import { ResponseMessages } from '@credebl/common/response-messages';
2323
import { ClientProxy, RpcException } from '@nestjs/microservices';
2424
import { map } from 'rxjs';
2525
import { getAgentUrl } from '@credebl/common/common.utils';
26-
import { credential_templates, oidc_issuer, user } from '@prisma/client';
26+
import { credential_templates, oidc_issuer, SignerOption, user } from '@prisma/client';
2727
import {
2828
IAgentOIDCIssuerCreate,
2929
IssuerCreation,
@@ -57,6 +57,7 @@ import {
5757
buildCredentialOfferUrl,
5858
CredentialOfferPayload
5959
} from '../libs/helpers/credential-sessions.builder';
60+
import { x5cKeyType } from '@credebl/enum/enum';
6061

6162
type CredentialDisplayItem = {
6263
logo?: { uri: string; alt_text?: string };
@@ -222,27 +223,15 @@ export class Oid4vcIssuanceService {
222223
}
223224
}
224225

225-
async oidcIssuers(orgId: string): Promise<IssuerResponse[]> {
226+
async oidcIssuers(orgId: string): Promise<oidc_issuer[]> {
226227
try {
227228
const agentDetails = await this.oid4vcIssuanceRepository.getAgentEndPoint(orgId);
228229
if (!agentDetails?.agentEndPoint) {
229230
throw new NotFoundException(ResponseMessages.issuance.error.agentEndPointNotFound);
230231
}
232+
const getIssuers = await this.oid4vcIssuanceRepository.getAllOidcIssuersByOrg(orgId);
231233

232-
const url = await getAgentUrl(agentDetails.agentEndPoint, CommonConstants.OIDC_GET_ALL_ISSUERS);
233-
const issuersDetails = await this._oidcGetIssuers(url, orgId);
234-
if (!issuersDetails || null == issuersDetails.response) {
235-
throw new InternalServerErrorException('Error from agent while oidcIssuers');
236-
}
237-
//TODO: Fix the response type from agent
238-
const raw = issuersDetails.response as unknown;
239-
const response: IssuerResponse[] =
240-
'string' === typeof raw ? (JSON.parse(raw) as IssuerResponse[]) : (raw as IssuerResponse[]);
241-
242-
if (!Array.isArray(response)) {
243-
throw new InternalServerErrorException('Invalid issuer payload from agent');
244-
}
245-
return response;
234+
return getIssuers;
246235
} catch (error: any) {
247236
const msg = error?.message ?? 'unknown error';
248237
this.logger.error(`[oidcIssuers] - error in oidcIssuers: ${msg}`);
@@ -294,13 +283,14 @@ export class Oid4vcIssuanceService {
294283
const metadata = {
295284
name,
296285
description,
297-
format,
286+
format: format.toString(),
298287
canBeRevoked,
299288
attributes,
300289
appearance: appearance ?? {},
301290
issuerId,
302291
signerOption
303292
};
293+
console.log(`service - createTemplate: `, issuerId);
304294
// Persist in DB
305295
const createdTemplate = await this.oid4vcIssuanceRepository.createTemplate(issuerId, metadata);
306296
if (!createdTemplate) {
@@ -473,14 +463,45 @@ export class Oid4vcIssuanceService {
473463

474464
//TDOD: signerOption should be under credentials change this with x509 support
475465
const signerOptions = [];
476-
getAllOfferTemplates.forEach((template) => {
477-
if (template.signerOption === SignerMethodOption.DID) {
466+
for (const template of getAllOfferTemplates) {
467+
if (template.signerOption === SignerOption.DID) {
478468
signerOptions.push({
479469
method: SignerMethodOption.DID,
480470
did: agentDetails.orgDid
481471
});
482472
}
483-
});
473+
474+
if (template.signerOption == SignerOption.X509_P256) {
475+
const activeCertificate = await this.oid4vcIssuanceRepository.getCurrentActiveCertificate(
476+
orgId,
477+
x5cKeyType.P256
478+
);
479+
480+
if (!activeCertificate) {
481+
throw new NotFoundException('No active certificate(p256) found for issuer');
482+
}
483+
signerOptions.push({
484+
method: SignerMethodOption.X5C,
485+
x5c: [activeCertificate.certificateBase64]
486+
});
487+
}
488+
489+
if (template.signerOption == SignerOption.X509_ED25519) {
490+
const activeCertificate = await this.oid4vcIssuanceRepository.getCurrentActiveCertificate(
491+
orgId,
492+
x5cKeyType.Ed25519
493+
);
494+
495+
if (!activeCertificate) {
496+
throw new NotFoundException('No active certificate(ed25519) found for issuer');
497+
}
498+
signerOptions.push({
499+
method: SignerMethodOption.X5C,
500+
x5c: [activeCertificate.certificateBase64]
501+
});
502+
}
503+
}
504+
console.log(`Setup signerOptions `, signerOptions);
484505
//TODO: Implement x509 support and discuss with team
485506
const buildOidcCredentialOffer: CredentialOfferPayload = buildCredentialOfferPayload(
486507
createOidcCredentialOffer,

libs/prisma-service/prisma/migrations/20250814141522_add_supported_protocol/migration.sql

Lines changed: 0 additions & 94 deletions
This file was deleted.

libs/prisma-service/prisma/migrations/20251013125236_added_x509_certificate_table/migration.sql

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,3 @@
1-
/*
2-
Warnings:
3-
4-
- You are about to drop the column `supported_protocol` on the `ledgers` table. All the data in the column will be lost.
5-
- You are about to drop the column `supported_protocol` on the `organisation` table. All the data in the column will be lost.
6-
7-
*/
8-
-- AlterTable
9-
ALTER TABLE "ledgers" DROP COLUMN "supported_protocol";
10-
11-
-- AlterTable
12-
ALTER TABLE "organisation" DROP COLUMN "supported_protocol";
13-
14-
-- DropEnum
15-
DROP TYPE "CredentialExchangeProtocol";
161

172
-- CreateTable
183
CREATE TABLE "oid4vc_credentials" (
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/*
2+
Warnings:
3+
4+
- The values [did,x509] on the enum `SignerOption` will be removed. If these variants are still used in the database, this will fail.
5+
6+
*/
7+
-- AlterEnum
8+
BEGIN;
9+
CREATE TYPE "SignerOption_new" AS ENUM ('DID', 'X509_P256', 'X509_ED25519');
10+
ALTER TABLE "credential_templates" ALTER COLUMN "signerOption" TYPE "SignerOption_new" USING ("signerOption"::text::"SignerOption_new");
11+
ALTER TYPE "SignerOption" RENAME TO "SignerOption_old";
12+
ALTER TYPE "SignerOption_new" RENAME TO "SignerOption";
13+
DROP TYPE "SignerOption_old";
14+
COMMIT;

libs/prisma-service/prisma/schema.prisma

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -601,8 +601,9 @@ model oid4vc_credentials {
601601
}
602602

603603
enum SignerOption {
604-
did
605-
x509
604+
DID
605+
X509_P256
606+
X509_ED25519
606607
}
607608

608609
model credential_templates {

0 commit comments

Comments
 (0)