From c45b39060fe8e6e5360e3b903f041fcbf956685d Mon Sep 17 00:00:00 2001
From: sivanov <sivanov.ctr@virtru.com>
Date: Mon, 7 Aug 2023 13:57:24 +0300
Subject: [PATCH 1/2] draft

---
 lib/package.json             |  2 +-
 lib/tdf3/src/client/index.ts |  4 ++++
 lib/tdf3/src/tdf.ts          | 21 ++++++++++++++++++---
 3 files changed, 23 insertions(+), 4 deletions(-)

diff --git a/lib/package.json b/lib/package.json
index b2dcbf00..995d6b18 100644
--- a/lib/package.json
+++ b/lib/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@opentdf/client",
-  "version": "1.2.1",
+  "version": "1.2.3",
   "description": "Access and generate tdf protected content",
   "homepage": "https://github.com/opentdf/client-web",
   "bugs": {
diff --git a/lib/tdf3/src/client/index.ts b/lib/tdf3/src/client/index.ts
index 53f5b9d2..9238b31d 100644
--- a/lib/tdf3/src/client/index.ts
+++ b/lib/tdf3/src/client/index.ts
@@ -370,6 +370,10 @@ export class Client {
     if (eo) {
       tdf.setEntity(eo);
     }
+    tdf.dpopEnabled = this.dpopEnabled;
+    if (sessionKeys.signingKeys) {
+      tdf.requestSignerKeyPair = sessionKeys.signingKeys;
+    }
     await tdf.addKeyAccess({
       type: offline ? 'wrapped' : 'remote',
       url: this.kasEndpoint,
diff --git a/lib/tdf3/src/tdf.ts b/lib/tdf3/src/tdf.ts
index 9dbca0f4..e90a2339 100644
--- a/lib/tdf3/src/tdf.ts
+++ b/lib/tdf3/src/tdf.ts
@@ -3,9 +3,14 @@ import { EventEmitter } from 'events';
 import axios from 'axios';
 import crc32 from 'buffer-crc32';
 import { v4 } from 'uuid';
-import { exportSPKI, importPKCS8, importX509 } from 'jose';
+import { exportSPKI, importPKCS8, importX509, KeyLike } from 'jose';
 import { DecoratedReadableStream } from './client/DecoratedReadableStream.js';
 import { EntityObject } from '../../src/tdf/EntityObject.js';
+import {
+  enums as cryptoEnums,
+} from '../../src/nanotdf-crypto/index.js';
+
+const { AlgorithmName } = cryptoEnums;
 
 import {
   AttributeSet,
@@ -127,6 +132,7 @@ export class TDF extends EventEmitter {
   contentStream?: ReadableStream<Uint8Array>;
   manifest?: Manifest;
   entity?: EntityObject;
+  dpopEnabled?: Boolean;
   encryptionInformation?: SplitKey;
   htmlTransferUrl?: string;
   authProvider?: AuthProvider | AppIdAuthProvider;
@@ -138,6 +144,7 @@ export class TDF extends EventEmitter {
   segmentSizeDefault: number;
   chunkMap: Map<string, Chunk>;
   cryptoService: CryptoService;
+  requestSignerKeyPair?: Required<Readonly<CryptoKeyPair>>;
 
   constructor(configuration: TDFConfiguration) {
     super();
@@ -520,7 +527,7 @@ export class TDF extends EventEmitter {
 
         //TODO I dont' think we need a body at all for KAS requests
         // Do we need ANY of this if it's already embedded in the EO in the Bearer OIDC token?
-        const body: Record<string, unknown> = {
+        let body: Record<string, unknown> = {
           keyAccess: keyAccessObject,
           policy: unsavedManifest.encryptionInformation.policy,
           entity: isAppIdProviderCheck(this.authProvider) ? this.entity : undefined,
@@ -532,7 +539,15 @@ export class TDF extends EventEmitter {
         if (isAppIdProviderCheck(this.authProvider)) {
           body.authToken = await reqSignature({}, pkKeyLike);
         } else {
-          body.clientPayloadSignature = await reqSignature(body, pkKeyLike);
+          body.clientPublicKey = this.publicKey;
+          body = {
+            signedRequestToken: await reqSignature(
+              { requestBody: JSON.stringify(body)},
+              (this.requestSignerKeyPair?.privateKey as KeyLike),
+              { alg: AlgorithmName.ES256, }
+            )
+          }
+          // body.clientPayloadSignature = await reqSignature(body, pkKeyLike);
         }
         const httpReq = await this.authProvider.withCreds(this.buildRequest('POST', url, body));
 

From 0a27679634ee5cbb9e53798f9fee13fec07846e3 Mon Sep 17 00:00:00 2001
From: sivanov <sivanov.ctr@virtru.com>
Date: Mon, 7 Aug 2023 17:42:56 +0300
Subject: [PATCH 2/2] should work but it doesnt

---
 lib/package.json             |  4 +++-
 lib/src/nanotdf/Client.ts    |  5 ++++-
 lib/tdf3/src/client/index.ts | 14 ++++++++++----
 lib/tdf3/src/tdf.ts          |  5 ++++-
 4 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/lib/package.json b/lib/package.json
index 995d6b18..8765d7fe 100644
--- a/lib/package.json
+++ b/lib/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@opentdf/client",
-  "version": "1.2.3",
+  "version": "1.2.7",
   "description": "Access and generate tdf protected content",
   "homepage": "https://github.com/opentdf/client-web",
   "bugs": {
@@ -10,6 +10,8 @@
     "dist/*/src/**",
     "dist/*/tdf3/**",
     "dist/*/*.json",
+    "src/**",
+    "tdf3/**",
     "README.md"
   ],
   "repository": {
diff --git a/lib/src/nanotdf/Client.ts b/lib/src/nanotdf/Client.ts
index f8383aac..a54a4359 100644
--- a/lib/src/nanotdf/Client.ts
+++ b/lib/src/nanotdf/Client.ts
@@ -213,7 +213,10 @@ export default class Client {
 
       const jwtPayload = { requestBody: requestBodyStr };
       const requestBody = {
-        signedRequestToken: await reqSignature(jwtPayload, this.requestSignerKeyPair.privateKey, {
+        signedRequestToken: await reqSignature(
+          jwtPayload,
+          this.requestSignerKeyPair.privateKey,
+          {
           alg: AlgorithmName.ES256,
         }),
       };
diff --git a/lib/tdf3/src/client/index.ts b/lib/tdf3/src/client/index.ts
index 9238b31d..d7353039 100644
--- a/lib/tdf3/src/client/index.ts
+++ b/lib/tdf3/src/client/index.ts
@@ -14,6 +14,7 @@ import { OIDCRefreshTokenProvider } from '../../../src/auth/oidc-refreshtoken-pr
 import { OIDCExternalJwtProvider } from '../../../src/auth/oidc-externaljwt-provider.js';
 import { CryptoService, PemKeyPair } from '../crypto/declarations.js';
 import { AuthProvider, AppIdAuthProvider, HttpRequest } from '../../../src/auth/auth.js';
+import { generateKeyPair, enums as cryptoEnums, cryptoPublicToPem } from '../../../src/nanotdf-crypto/index.js';
 import EAS from '../../../src/auth/Eas.js';
 
 import { EncryptParams, DecryptParams, type Scope } from './builders.js';
@@ -28,7 +29,6 @@ import {
 import * as defaultCryptoService from '../crypto/index.js';
 import { Policy } from '../models/index.js';
 import { TdfError } from '../errors.js';
-import { rsaPkcs1Sha256 } from '../crypto/index.js';
 
 const GLOBAL_BYTE_LIMIT = 64 * 1000 * 1000 * 1000; // 64 GB, see WS-9363.
 const HTML_BYTE_LIMIT = 100 * 1000 * 1000; // 100 MB, see WS-9476.
@@ -137,7 +137,12 @@ export async function createSessionKeys({
   let signingKeys;
 
   if (dpopEnabled) {
-    signingKeys = await crypto.subtle.generateKey(rsaPkcs1Sha256(), true, ['sign']);
+    signingKeys = await generateKeyPair({
+      type: cryptoEnums.AlgorithmName.ECDSA,
+      curve: cryptoEnums.NamedCurve.P256,
+      keyUsages: [cryptoEnums.KeyUsageType.Sign, cryptoEnums.KeyUsageType.Verify],
+      isExtractable: true,
+    });
   }
 
   // This will contact the auth server and forcibly refresh the auth token claims,
@@ -145,8 +150,9 @@ export async function createSessionKeys({
   // Note that we base64 encode the PEM string here as a quick workaround, simply because
   // a formatted raw PEM string isn't a valid header value and sending it raw makes keycloak's
   // header parser barf. There are more subtle ways to solve this, but this works for now.
-  if (authProvider && !isAppIdProviderCheck(authProvider)) {
-    await authProvider?.updateClientPublicKey(base64.encode(k2.publicKey), signingKeys);
+  if (authProvider && !isAppIdProviderCheck(authProvider) && signingKeys) {
+    const signerPubKey = await cryptoPublicToPem(signingKeys.publicKey);
+    await authProvider?.updateClientPublicKey(base64.encode(signerPubKey), signingKeys);
   }
   return { keypair: k2, signingKeys };
 }
diff --git a/lib/tdf3/src/tdf.ts b/lib/tdf3/src/tdf.ts
index e90a2339..eba9d518 100644
--- a/lib/tdf3/src/tdf.ts
+++ b/lib/tdf3/src/tdf.ts
@@ -6,6 +6,8 @@ import { v4 } from 'uuid';
 import { exportSPKI, importPKCS8, importX509, KeyLike } from 'jose';
 import { DecoratedReadableStream } from './client/DecoratedReadableStream.js';
 import { EntityObject } from '../../src/tdf/EntityObject.js';
+import DefaultParams from './../../src/nanotdf/models/DefaultParams.js';
+
 import {
   enums as cryptoEnums,
 } from '../../src/nanotdf-crypto/index.js';
@@ -528,6 +530,7 @@ export class TDF extends EventEmitter {
         //TODO I dont' think we need a body at all for KAS requests
         // Do we need ANY of this if it's already embedded in the EO in the Bearer OIDC token?
         let body: Record<string, unknown> = {
+          algorithm: DefaultParams.defaultECAlgorithm,
           keyAccess: keyAccessObject,
           policy: unsavedManifest.encryptionInformation.policy,
           entity: isAppIdProviderCheck(this.authProvider) ? this.entity : undefined,
@@ -862,7 +865,7 @@ export class TDF extends EventEmitter {
         const url = `${keySplitInfo.url}/${isAppIdProvider ? '' : 'v2'}/rewrap`;
 
         const requestBodyStr = JSON.stringify({
-          algorithm: 'RS256',
+          algorithm: DefaultParams.defaultECAlgorithm,
           keyAccess: keySplitInfo,
           policy: manifest.encryptionInformation.policy,
           clientPublicKey: this.publicKey,