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

refactor: [SIW-1176] Change decoded assertion format on iOS #17

Merged
merged 9 commits into from
Jun 5, 2024
9 changes: 6 additions & 3 deletions backend/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,13 @@
* The server then verifies the assertion using the stored public key.
* The server also verifies the signCount and stores the new signCount.
*/
app.post(`/assertion/verify`, (req, res) => {
try {
const { hardwareKeyTag, assertion } = req.body;
const { hardwareKeyTag } = req.body;

if (hardwareKeyTag === undefined || assertion === undefined) {
console.log(req.body);
Fixed Show fixed Hide fixed

if (hardwareKeyTag === undefined) {
Dismissed Show dismissed Hide dismissed
throw new Error('Invalid authentication');
}

Expand All @@ -102,7 +104,8 @@
}

const result = verifyAssertion({
assertion: Buffer.from(assertion, 'base64').toString('utf-8'),
signature: req.body.signature,
authenticatorData: req.body.authenticatorData,
payload: req.body.payload,
publicKey: attestation.publicKey,
bundleIdentifier: BUNDLE_IDENTIFIER,
Expand Down
21 changes: 12 additions & 9 deletions backend/src/verifyAssertion.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { createHash, createVerify } from 'crypto';

export type VerifyAssertionParams = {
assertion: string;
signature: string;
authenticatorData: string;
payload: Buffer;
publicKey: string;
bundleIdentifier: string;
Expand All @@ -16,7 +17,8 @@ export type VerifyAssertionParams = {
*/
const verifyAssertion = (params: VerifyAssertionParams) => {
const {
assertion,
signature,
authenticatorData,
payload,
publicKey,
bundleIdentifier,
Expand All @@ -32,8 +34,12 @@ const verifyAssertion = (params: VerifyAssertionParams) => {
throw new Error('teamIdentifier is required');
}

if (!assertion) {
throw new Error('assertion is required');
if (!signature) {
throw new Error('signature is required');
}

if (!authenticatorData) {
throw new Error('authenticatorData is required');
}

if (!payload) {
Expand All @@ -44,11 +50,8 @@ const verifyAssertion = (params: VerifyAssertionParams) => {
throw new Error('publicKey is required');
}

// 1. Get signature and authenticator data from the assertion.
const { signature, authenticatorData } = JSON.parse(assertion);

const sign = Buffer.from(signature);
const authData = Buffer.from(authenticatorData);
const sign = Buffer.from(signature, 'base64');
const authData = Buffer.from(authenticatorData, 'base64');
// 2. Compute the SHA256 hash of the client data, and store it as clientDataHash.
const clientDataHash = createHash('sha256').update(payload).digest();

Expand Down
4 changes: 3 additions & 1 deletion example/src/IosApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,13 @@ export default function App() {
if (assertion) {
// decode CBOR assertion on native side (iOS only)
const decodedAssertion = await decodeAssertion(assertion);
console.log(decodedAssertion);
// verify attestation on the server with POST
// and body of challenge, attestation and keyId
const result = await postRequest('assertion/verify', {
challenge: challenge,
assertion: decodedAssertion,
signature: decodedAssertion.signature,
authenticatorData: decodedAssertion.authenticatorData,
hardwareKeyTag: hardwareKeyTag,
payload: JSON.stringify({ challenge: challenge, jwk: jwk }),
});
Expand Down
14 changes: 5 additions & 9 deletions ios/IoReactNativeIntegrity.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,6 @@ import SwiftCBOR
class IoReactNativeIntegrity: NSObject {
private typealias ME = ModuleException

struct DecodedData: Codable {
var signature: [UInt8]
var authenticatorData: [UInt8]
}

enum CBORDecodingError: Error {
case invalidFormat(String)
}
Expand Down Expand Up @@ -46,12 +41,13 @@ class IoReactNativeIntegrity: NSObject {
case let .byteString(authenticatorDataBytes)? = map["authenticatorData"] else {
throw CBORDecodingError.invalidFormat("Expected signature and authenticatorData in the CBOR map")
}

let decodedData = DecodedData(signature: signatureBytes, authenticatorData: authenticatorDataBytes)

let jsonData = try JSONEncoder().encode(decodedData)
let decodedData: [String:String] = [
"signature": Data(signatureBytes).base64EncodedString(),
"authenticatorData": Data(authenticatorDataBytes).base64EncodedString()
]

resolve(jsonData.base64EncodedString())
resolve(decodedData)
} catch {
ME.decodingAssertionFailed.reject(reject: reject, ("error", error.localizedDescription))
}
Expand Down
4 changes: 3 additions & 1 deletion src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,9 @@ export function generateHardwareSignatureWithAssertion(
* @param assertion - the CBOR assertion to be decoded
* @returns - a promise that resolves to a string.
*/
export function decodeAssertion(assertion: string): Promise<string> {
export function decodeAssertion(
assertion: string
): Promise<{ signature: string; authenticatorData: string }> {
return IoReactNativeIntegrity.decodeAssertion(assertion);
}

Expand Down
Loading