summaryrefslogtreecommitdiffhomepage
path: root/packages/server/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/server/src')
-rw-r--r--packages/server/src/authentication/verifyAuthenticationResponse.test.ts3
-rw-r--r--packages/server/src/authentication/verifyAuthenticationResponse.ts5
-rw-r--r--packages/server/src/helpers/matchExpectedRPID.ts13
-rw-r--r--packages/server/src/registration/verifyRegistrationResponse.test.ts19
-rw-r--r--packages/server/src/registration/verifyRegistrationResponse.ts7
5 files changed, 41 insertions, 6 deletions
diff --git a/packages/server/src/authentication/verifyAuthenticationResponse.test.ts b/packages/server/src/authentication/verifyAuthenticationResponse.test.ts
index 5547224..c996991 100644
--- a/packages/server/src/authentication/verifyAuthenticationResponse.test.ts
+++ b/packages/server/src/authentication/verifyAuthenticationResponse.test.ts
@@ -45,6 +45,7 @@ test('should return authenticator info after verification', async () => {
expect(verification.authenticationInfo.newCounter).toEqual(144);
expect(verification.authenticationInfo.credentialID).toEqual(authenticator.credentialID);
expect(verification.authenticationInfo?.origin).toEqual(assertionOrigin);
+ expect(verification.authenticationInfo?.rpID).toEqual('dev.dontneeda.pw');
});
test('should throw when response challenge is not expected value', async () => {
@@ -226,6 +227,7 @@ test('should support multiple possible origins', async () => {
expect(verification.verified).toEqual(true);
expect(verification.authenticationInfo?.origin).toEqual(assertionOrigin);
+ expect(verification.authenticationInfo?.rpID).toEqual('dev.dontneeda.pw');
});
test('should throw an error if origin not in list of expected origins', async () => {
@@ -375,6 +377,7 @@ test('should return credential backup info', async () => {
expect(verification.authenticationInfo?.credentialDeviceType).toEqual('singleDevice');
expect(verification.authenticationInfo?.credentialBackedUp).toEqual(false);
expect(verification.authenticationInfo?.origin).toEqual(assertionOrigin);
+ expect(verification.authenticationInfo?.rpID).toEqual('dev.dontneeda.pw');
});
/**
diff --git a/packages/server/src/authentication/verifyAuthenticationResponse.ts b/packages/server/src/authentication/verifyAuthenticationResponse.ts
index bfc5bf5..c9f23ca 100644
--- a/packages/server/src/authentication/verifyAuthenticationResponse.ts
+++ b/packages/server/src/authentication/verifyAuthenticationResponse.ts
@@ -154,7 +154,7 @@ export async function verifyAuthenticationResponse(
expectedRPIDs = expectedRPID;
}
- await matchExpectedRPID(rpIdHash, expectedRPIDs);
+ const matchedRPID = await matchExpectedRPID(rpIdHash, expectedRPIDs);
if (advancedFIDOConfig !== undefined) {
const { userVerification: fidoUserVerification } = advancedFIDOConfig;
@@ -216,6 +216,7 @@ export async function verifyAuthenticationResponse(
credentialBackedUp,
authenticatorExtensionResults: extensionsData,
origin: clientDataJSON.origin,
+ rpID: matchedRPID,
},
};
@@ -238,6 +239,7 @@ export async function verifyAuthenticationResponse(
* backed up. Always `false` for single-device credentials. **Should be kept in a DB for later
* reference!**
* @param authenticationInfo.origin The origin of the website that the authentication occurred on
+ * @param authenticationInfo.rpID The RP ID that the authentication occurred on
* @param authenticationInfo?.authenticatorExtensionResults The authenticator extensions returned
* by the browser
*/
@@ -250,6 +252,7 @@ export type VerifiedAuthenticationResponse = {
credentialDeviceType: CredentialDeviceType;
credentialBackedUp: boolean;
origin: string;
+ rpID: string;
authenticatorExtensionResults?: AuthenticationExtensionsAuthenticatorOutputs;
};
};
diff --git a/packages/server/src/helpers/matchExpectedRPID.ts b/packages/server/src/helpers/matchExpectedRPID.ts
index be49fc2..c08c223 100644
--- a/packages/server/src/helpers/matchExpectedRPID.ts
+++ b/packages/server/src/helpers/matchExpectedRPID.ts
@@ -2,19 +2,22 @@ import { toHash } from './toHash';
import { isoUint8Array } from './iso';
/**
- * Go through each expected RP ID and try to find one that matches. Raises an Error if no
+ * Go through each expected RP ID and try to find one that matches. Returns the unhashed RP ID
+ * that matched the hash in the response.
+ *
+ * Raises an `UnexpectedRPIDHash` error if no match is found
*/
export async function matchExpectedRPID(
rpIDHash: Uint8Array,
expectedRPIDs: string[],
-): Promise<void> {
+): Promise<string> {
try {
- await Promise.any(
+ const matchedRPID = await Promise.any<string>(
expectedRPIDs.map(expected => {
return new Promise((resolve, reject) => {
toHash(isoUint8Array.fromASCIIString(expected)).then(expectedRPIDHash => {
if (isoUint8Array.areEqual(rpIDHash, expectedRPIDHash)) {
- resolve(true);
+ resolve(expected);
} else {
reject();
}
@@ -22,6 +25,8 @@ export async function matchExpectedRPID(
});
}),
);
+
+ return matchedRPID;
} catch (err) {
const _err = err as Error;
diff --git a/packages/server/src/registration/verifyRegistrationResponse.test.ts b/packages/server/src/registration/verifyRegistrationResponse.test.ts
index 2b973e5..e6acd2a 100644
--- a/packages/server/src/registration/verifyRegistrationResponse.test.ts
+++ b/packages/server/src/registration/verifyRegistrationResponse.test.ts
@@ -70,6 +70,7 @@ test('should verify FIDO U2F attestation', async () => {
isoBase64URL.toBuffer(attestationFIDOU2F.response.attestationObject),
);
expect(verification.registrationInfo?.origin).toEqual('https://dev.dontneeda.pw');
+ expect(verification.registrationInfo?.rpID).toEqual('dev.dontneeda.pw');
});
test('should verify Packed (EC2) attestation', async () => {
@@ -177,6 +178,7 @@ test('should verify None attestation w/RSA public key', async () => {
isoBase64URL.toBuffer('kGXv4RJWLeXRw8Yf3T22K3Gq_GGeDv9OKYmAHLm0Ylo'),
);
expect(verification.registrationInfo?.origin).toEqual('https://dev.dontneeda.pw');
+ expect(verification.registrationInfo?.rpID).toEqual('dev.dontneeda.pw');
});
test('should throw when response challenge is not expected value', async () => {
@@ -419,6 +421,7 @@ test('should validate TPM RSA response (SHA256)', async () => {
isoBase64URL.toBuffer('lGkWHPe88VpnNYgVBxzon_MRR9-gmgODveQ16uM_bPM'),
);
expect(verification.registrationInfo?.origin).toEqual('https://dev.dontneeda.pw');
+ expect(verification.registrationInfo?.rpID).toEqual('dev.dontneeda.pw');
});
test('should validate TPM RSA response (SHA1)', async () => {
@@ -455,6 +458,7 @@ test('should validate TPM RSA response (SHA1)', async () => {
isoBase64URL.toBuffer('oELnad0f6-g2BtzEn_78iLNoubarlq0xFtOtAMXnflU'),
);
expect(verification.registrationInfo?.origin).toEqual('https://dev.dontneeda.pw');
+ expect(verification.registrationInfo?.rpID).toEqual('dev.dontneeda.pw');
});
test('should validate Android-Key response', async () => {
@@ -491,6 +495,7 @@ test('should validate Android-Key response', async () => {
isoBase64URL.toBuffer('PPa1spYTB680cQq5q6qBtFuPLLdG1FQ73EastkT8n0o'),
);
expect(verification.registrationInfo?.origin).toEqual('https://dev.dontneeda.pw');
+ expect(verification.registrationInfo?.rpID).toEqual('dev.dontneeda.pw');
});
test('should support multiple possible origins', async () => {
@@ -503,6 +508,20 @@ test('should support multiple possible origins', async () => {
expect(verification.verified).toBe(true);
expect(verification.registrationInfo?.origin).toEqual('https://dev.dontneeda.pw');
+ expect(verification.registrationInfo?.rpID).toEqual('dev.dontneeda.pw');
+});
+
+test('should not set RPID in registrationInfo when not expected', async () => {
+ const verification = await verifyRegistrationResponse({
+ response: attestationNone,
+ expectedChallenge: attestationNoneChallenge,
+ expectedOrigin: 'https://dev.dontneeda.pw',
+ expectedRPID: undefined,
+ });
+
+ expect(verification.verified).toBe(true);
+ expect(verification.registrationInfo?.origin).toEqual('https://dev.dontneeda.pw');
+ expect(verification.registrationInfo?.rpID).toBeUndefined();
});
test('should throw an error if origin not in list of expected origins', async () => {
diff --git a/packages/server/src/registration/verifyRegistrationResponse.ts b/packages/server/src/registration/verifyRegistrationResponse.ts
index 5a52f6a..d33cdea 100644
--- a/packages/server/src/registration/verifyRegistrationResponse.ts
+++ b/packages/server/src/registration/verifyRegistrationResponse.ts
@@ -141,6 +141,7 @@ export async function verifyRegistrationResponse(
parsedAuthData;
// Make sure the response's RP ID is ours
+ let matchedRPID: string | undefined;
if (expectedRPID) {
let expectedRPIDs: string[] = [];
if (typeof expectedRPID === 'string') {
@@ -149,7 +150,7 @@ export async function verifyRegistrationResponse(
expectedRPIDs = expectedRPID;
}
- await matchExpectedRPID(rpIdHash, expectedRPIDs);
+ matchedRPID = await matchExpectedRPID(rpIdHash, expectedRPIDs);
}
// Make sure someone was physically present
@@ -247,6 +248,7 @@ export async function verifyRegistrationResponse(
credentialDeviceType,
credentialBackedUp,
origin: clientDataJSON.origin,
+ rpID: matchedRPID,
authenticatorExtensionResults: extensionsData,
};
}
@@ -275,6 +277,8 @@ export async function verifyRegistrationResponse(
* backed up. Always `false` for single-device credentials. **Should be kept in a DB for later
* reference!**
* @param registrationInfo.origin The origin of the website that the registration occurred on
+ * @param registrationInfo?.rpID The RP ID that the registration occurred on, if one or more were
+ * specified in the registration options
* @param registrationInfo?.authenticatorExtensionResults The authenticator extensions returned
* by the browser
*/
@@ -292,6 +296,7 @@ export type VerifiedRegistrationResponse = {
credentialDeviceType: CredentialDeviceType;
credentialBackedUp: boolean;
origin: string;
+ rpID?: string;
authenticatorExtensionResults?: AuthenticationExtensionsAuthenticatorOutputs;
};
};