021. Web API for accessing FIDO 2.0 credentials - FIDO Authenticator model

FIDO 2.0 Web API for accessing FIDO 2.0 credentials

FIDO의 3가지 스펙 문서 중 두 번째인 Signature Format에 대해서 정리한다.

참고 FIDO alliance : FIDO 2.0 Web API 문서

FIDO Credential API - FIDOCredentials

이번 포스팅에서는 FIDO 2.0의 Credential을 생성하고 사용하기 위한 API 규범을 소개한다.

Credential의 삭제는 의도적으로 생략되어 있으며 별도의 스크립트가 아닌 각각의 플랫폼에 따라 특정 사용자 인터페이스를 통해 수행할 것으로 예상되기 때문이다.

FIDO Credential API의 기본적인 아이디어는 Credential이 사용자의 것이며 브라우저나 플랫폼은 단순히 이를 관리하는 것에서 출발한다.

원본 스크립트는 추후 브라우저를 통해 사용자의 동의하에 스크립트를 사용하기 위한 새로운 Credential을 만들거나, 플랫폼에서 기존에 보유하고 있는 Credential을 사용하여 인증 작업을 진행하도록 요청할 수 있다.

그러나 모든 작업은 사용자를 대신하여 브라우저나 플랫폼에 의해 제어되며, 어떤 시점에서도 스크립트 스스로 Credential 자체에 접근할 수는 없다.

단순히 스크립트는 Credential에 대해 객체 형태로 정보를 얻을 수 있을 뿐이다.

사용자 에이전트는 powerful-features에 정의된 대로 API를 호출 객체의 안전하지 않은 Context에만 노출하도록 해야 한다.

앞으로는 FIDO Credential API는 W3C에서 관리하는 Credential의 관리를 위한 더욱 많은 일반 Web API프레임워크와 통합될 수 있으며, 이 통합은 대부분 중간 인터페이스 및 dictionary type을 작성하도록 하여 이 포스팅의 유형이 상속될 것이다.

중요한 것은 통합이 진행된다고 하더라도 FIDO를 개발하는 개발자나 이용하는 사용자의 경험을 해칠 정도로 크게 변경되지는 않을 것이다.

통합을 진행되는 동안 이 스펙문서는 쉬운 검토를 위해 최소한의 형식을 유지할 것이다.

FIDO Credential API는 아래와 같은 형태로 정의될 것이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
partial interface Window {
readonly attribute FIDOCredentials fido;
};

interface FIDOCredentials {
Promise < FidoCredentialInfo > makeCredential(
Account account,
sequence < FIDOCredentialParamters > cryptoParameters,
DOMString attestationChallenge,
optional unsigned long timeoutSeconds,
optional sequence < Credential > blacklist,
optional FIDOExtensions extensions
);

Promise < FIDOAssertion > getAssertion(
DOMString assertionChallenge,
optional unsigned long timeoutSeconds,
optional sequence < Credential > whitelist,
optional FIDOExtensions extensions
);
};

interface FIDOCredentialInfo {
readonly attribute Credential credential;
readonly attribute AlgorithmIdentifier algorithm;
readonly attribute any publicKey;
readonly attribute AttestationStatement attestation;
};

dictionary Account {
required DOMString rpDisplayName;
required DOMString displayName;
DOMString name;
DOMString id;
DOMString imageUri;
};

dictionary FIDOCredentialParameters {
required CredentialType type;
required AlgorithmIdentifier algorithm;
};

enum CredentialType {
"FIDO"
};

interface Credential {
readonly attribute CredentialType type;
readonly attribute DOMString id;
};

FIDOCredentials Interface

위의 인터페이스는 아래와 같이 정의된다.

Create a new credential(makeCredential method)

makeCredential 메소드를 통해 새로운 Credential을 생성할 수 있다.

이 메소드를 사용하면 스크립트가 사용자 에이전트에 지정된 유형으로 새로운 Credential을 생성하고 기본 플랫폼에게 Credential을 유지하도록 요청한다.

이때 브라우저나 OS에서 관리하는 데이터 저장소가 필요할 수도 있다.

사용자 에이전트는 사용자에게 Create a new credential 을 승인하라는 프롬프트 메시지를 띄워 사용자의 동의를 구한다.

사용자의 동의를 구하는 데 성공하면 새로 생성된 Credential을 명세하는 FIDOCredentialInfo 객체가 생성된다.

이 메소드는 아래의 6개 매개변수가 필요하다.

  • account
    account 매개변수는 Credential을 생성할 때 사용자의 계정에 대한 정보를 지정한다. 사용자 계정 정보는 추후 사용자가 Credential을 선택하라는 프롬프트 메시지를 표시할 때 authenticator에 의해 사용된다.

  • cryptoParameters
    cryptoParameters 매개변수는 생성할 Credential에서 원하는 특정 속성에 대한 정보를 제공해준다. 시퀀스는 가장 선호하는 순으로 정렬되어 제공되므로 플랫폼은 Credential을 생성할 때 가장 선호도가 높은 시퀀스를 이용해 가장 바람직한 Credential을 생성한다.

  • attestationChallenge
    attestationChallenge 매개변수는 새로 작성된 Credential의 Attestation Statement를 생성하기 위한 challenge 값을 가지고 있다.

  • timeoutSeconds
    timeoutSeconds 매개변수는 필수가 아닌 선택적 매개변수이다. 만약 timeoutSeconds 가 지정되면 이 메소드를 호출하고 호출이 완료될 때까지 기다릴 시간을 초단위로 지정하게 된다. 하지만 이 매개변수는 단순히 힌트값으로 플랫폼의 특성에 따라 오버라이드 처리될 가능성이 있다.

  • blacklist
    blacklist 매개변수는 필수가 아닌 선택적 매개변수이다.
    단일 authenticator에서 동일한 account 내 여러 개의 Credential에 대한 생성을 제한하고자 하는 Relying Party가 사용한다.
    특정 Authenticator이 새로운 Credential을 생성하려고 할 때 이미 Authenticator이 가지고 1개 이상의 Credential이 존재한다면 해당 플랫폼은 에러를 반환한다.

  • extensions
    extensions 매개변수는 필수가 아닌 선택적 매개변수이다.
    이 매개변수는 클라이언트와 Authenticator의 확장에 따른 추가 처리의 요청에 대한 값을 가진다.
    예를 들어 호출자가 새로운 Credential을 만드는 데 특정 기능을 가진 Authenticator만을 요청하거나 Attestation statement에 추가적인 정보를 반환하도록 요청하는 식이다.
    또 다른 방법으로 호출자가 Authenticator로 하여금 사용자에게 표시하도록 하는 프롬프트 메시지를 추가적으로 지정할 수 있다.

    참고 extensions은 Signature Format에 정의되어있다.

makeCredential 메소드를 실행하면 아래와 같은 알고리즘을 따라 동작한다.

  1. timeoutSeconds 가 지정되면 해당 값이 플랫폼에 정의된 적절한 범위내에 있는 값인지 확인한다. 만약 적절한 범위내에 없는 경우 범위내 가장 가까운 값으로 수정하여 adjustedTimeout 을 조정된 값으로 설정한다. timeoutSeconds 가 지정되지 않은 경우 adjustedTimeout 은 플랫폼 별 기본값으로 지정된다.

  2. 새로운 Promise 를 정하고 지정된 adjustedTimeout 값만큼 타이머를 설정한 후 해당 시간 경과후 Promise 를 반환하도록 한 뒤, 비동기적으로 아래의 순서대로 이어서 수행한다.

  3. callerOrigin 을 원본 호출자로 설정한다. 그 다음 callerOrigin 에서 RP ID를 추출하고 추출한 RP ID를 rpId 값으로 설정한다.

    참고 RP ID : Relying Party Identifier

  4. issuedRequests 를 비어 있는 목록으로 초기화한다.

  5. cryptoParameters 의 각 요소값들을 아래 순서대로 처리한다.
    a. current 를 현재 선택된 cryptoParameters 의 요소로 설정한다.
    b. 만약 current.type 에 현재 구현이 지원하는 CredentialType 이 없는 경우 이 프로세스를 중지하고 cryptoParameters 의 다음 요소로 이동한다.
    c. normalizedAlgorithmalgcurrent.algorithm 으로 opgenerateKey 로 설정하여 WebCrypto에 정의된 프로시저를 사용하여 알고리즘을 정규화한 결과값이다. 이 알고리즘 수행 중 오류가 발행하면 현재 프로세스를 중지하고 cryptoParameters 의 다음 요소로 이동한다.

  6. blacklist 가 정의되지 않았으면 비어 있는 목록으로 초기화한다.

  7. 만약 extensions 이 정의된 경우 클라이언트 플랫폼에서 모든 extension을 처리하여 authenticator에게 전송되어야 하는데, 이 데이터를 clientExtensions 이라고 정의한다.

  8. 현재 메소드가 동작중인 플랫폼에서 사용가능한 내장 및 외부 authenticator에 대하여 callerOrigin, rpId, account, current.type, normalizedAlgorithm, blacklist, attestationChallenge, clientExtensions 을 매개변수로 사용하여 해당 authenticator에 대해 authenticatorMakeCredential 메소드를 비동기로 실행시킨다. 이후 issuedRequests 에 해당 항목을 추가한다.

  9. issuedRequests 가 비어있는 동안, adjustedTimeout 타이머 및 authenticator의 응답에 따라 아래의 작업을 수행한다.
    a. adjustedTimeout 타이머가 만료된 경우, issuedRequests 의 각 항목에 대해 해당 authenticator의 authenticatorCancel 작업을 호출하고 목록에서 해당 항목을 제거한다.
    b. authenticator가 작업을 취소했음을 나타내는 상태를 반환하면 issuedRequests 에서 해당 authenticator의 항목을 삭제한 뒤 issuedRequests 의 나머지 각 항목에 대해 authenticatorCancel 작업을 호출하고 목록에서 제거한다.
    c. authenticator가 오류 상태를 반환하면 해당 요청을 issuedRequests 에서 제거한다.
    d. authenticator가 성공했음을 나타내는 경우 FIDOCredentialsInfo 라는 value 객체를 만들고 해당 필드를 authenticator에서 반환된 값으로 채운 뒤 Promise 를 resolve하고 알고리즘을 종료한다.

  10. 이름이 NoteFoundErrorDOMExceptionPromise 를 Resolve하고 알고리즘을 종료한다.

위의 알고리즘을 수행하는 과정에서 사용자 에이전트는 사용자에게 몇몇 UI를 표시하여 authenticator의 선택 및 승인을 받아야 한다.

User an existing credential(getAssertion method)

getAssertion 메소드를 통해 기존에 존재하는 FIDO 2.0 Credential을 사용자 동의하에 사용할 수 있다.

스크립트는 Credential을 허용할 몇 가지 기준을 선택적으로 지정한다.

사용자 에이전트나 플랫폼은 지정된 기준와 일치하는 Credential을 찾고 스크립트가 사용할 Credential을 선택하도록 안내한다.

사용자는 개인정보를 유지하기 위해 Credential을 제공하지 않을 수도 있다.

이 메소드는 아래의 4개 매개변수가 필요하다.

  • assertionChallenge
    assertionChallenge 매개변수는 선택된 authenticator가 서명할 것으로 예상되는 문자열을 포함한다.

  • timeoutSeconds
    timeoutSeconds 매개변수는 필수가 아닌 선택적 매개변수이다. 만약 timeoutSeconds 가 지정되면 이 메소드를 호출하고 호출이 완료될 때까지 기다릴 시간을 초단위로 지정하게 된다. 하지만 이 매개변수는 단순히 힌트값으로 플랫폼의 특성에 따라 오버라이드 처리될 가능성이 있다.

  • whitelist
    whitelist 매개변수는 필수가 아닌 선택적 매개변수이다.
    호출자가 승인할 수 있는 Credential 목록을 포함하며, 선호도가 높은 순서대로 목록을 정렬한다.

  • extensions
    extensions 매개변수는 필수가 아닌 선택적 매개변수이다.
    이 매개변수는 클라이언트와 Authenticator의 확장에 따른 추가 처리의 요청에 대한 값을 가진다.
    예를 들어 사용자로부터 트랜잭션 확인을 요청하면 프롬프트 문자열이 extension에 포함된다.
    extensions 는 companion 방식으로 정의된다.

getAssertion 메소드를 실행하면 아래와 같은 알고리즘을 따라 동작한다.

  1. timeoutSeconds 가 지정되면 해당 값이 플랫폼에 정의된 적절한 범위내에 있는 값인지 확인한다. 만약 적절한 범위내에 없는 경우 범위내 가장 가까운 값으로 수정하여 adjustedTimeout 을 조정된 값으로 설정한다. timeoutSeconds 가 지정되지 않은 경우 adjustedTimeout 은 플랫폼 별 기본값으로 지정된다.

  2. 새로운 Promise 를 정하고 지정된 adjustedTimeout 값만큼 타이머를 설정한 후 해당 시간 경과후 Promise 를 반환하도록 한 뒤, 비동기적으로 아래의 순서대로 이어서 수행한다.

  3. callerOrigin 을 원본 호출자로 설정한다. 그 다음 callerOrigin 에서 RP ID를 추출하고 추출한 RP ID를 rpId 값으로 설정한다.

    참고 RP ID : Relying Party Identifier

  4. issuedRequests 를 비어 있는 목록으로 초기화한다.

  5. 만약 extensions 이 정의된 경우 클라이언트 플랫폼에서 모든 extension을 처리하여 authenticator에게 전송되어야 하는데, 이 데이터를 clientExtensions 이라고 정의한다.

  6. 현재 메소드가 동작중인 플랫폼에서 사용가능한 내장 및 외부 authenticator에 대하여 아래 과정대로 동작을 수행한다.
    a. whitelist 가 정의되지 않았거나 비어있으면 credentialList 단일 wildcard 항목이 들어있는 목록으로 지정한다.
    b. whitelist 가 정의되었거나 비어있지 않으면 특정 플랫폼의 고유 절차를 선택적으로 실행하여 credential들 중 어떤 것이 해당 authenticator에 존재하고 있는지 판별한다. 그 뒤에 credentialList 를 필터링된 목록으로 지정한다. 만약 credentialList 가 비어있게 되면 authenticator를 무시하고 아래의 authenticator 과정을 수행하지 말아야 한다.
    c. authenticatorGetAssertion 를 비동기적으로 호출하여 callerOrigin, rpID, assertionChallenge, credentialList, clientExtensions 을 매개변수로 사용하여 authenticator가 인증을 받는다.
    d. issuedRequests 에 요청에 해당하는 항목을 추가한다.

  7. issuedRequests 가 비어있는 동안, adjustedTimeout 타이머 및 authenticator의 응답에 따라 아래의 작업을 수행한다.
    a. adjustedTimeout 타이머가 만료된 경우, issuedRequests 의 각 항목에 대해 해당 authenticator의 authenticatorCancel 작업을 호출하고 목록에서 해당 항목을 제거한다.
    b. authenticator가 작업을 취소했음을 나타내는 상태를 반환하면 issuedRequests 에서 해당 authenticator의 항목을 삭제한 뒤 issuedRequests 의 나머지 각 항목에 대해 authenticatorCancel 작업을 호출하고 목록에서 제거한다.
    c. authenticator가 오류 상태를 반환하면 해당 요청을 issuedRequests 에서 제거한다.
    d. authenticator가 성공했음을 나타내는 경우 FIDOAssertion 라는 value 객체를 만들고 해당 필드를 authenticator에서 반환된 값으로 채운 뒤 Promise 를 resolve하고 알고리즘을 종료한다.

  8. 이름이 NoteFoundErrorDOMExceptionPromise 를 Resolve하고 알고리즘을 종료한다.

위의 알고리즘을 수행하는 과정에서 사용자 에이전트는 사용자에게 몇몇 UI를 표시하여 작업을 완료할 authenticator룰 선택하고 권한을 부여받아야 한다.