Personal tools

Identity/BrowserID

From MozillaWiki

< Identity(Difference between revisions)
Jump to: navigation, search
(Main Protocol Flow)
(Certifying Users: Documenting user is not authenticated as target user)
(47 intermediate revisions by one user not shown)
Line 1: Line 1:
 
  
 
__TOC__
 
__TOC__
Line 8: Line 7:
 
== IN PROGRESS ==
 
== IN PROGRESS ==
  
This document is in progress. Please consult:
+
This document is in progress and is, in some respects, ahead of the actual BrowserID code. This document will be the single source of truth for BrowserID before 3/15/2012.
 
+
* [http://lloyd.io/how-browserid-works How BrowserID works]
+
* [http://lloyd.io/primary-identity-authorities-in-browserid Primary Identity Authorities in BrowserID]
+
* [http://identity.mozilla.com The Identity Team Blog]
+
 
+
Past blog posts contain a lot of information, for example: [http://identity.mozilla.com/post/11145921163/browserid-design-for-privacy BrowserID Design for Privacy]
+
 
+
  
 
== Overview ==
 
== Overview ==
  
This specification, BrowserID, defines a mechanism for websites to request, from the user via her user-agent, a signed assertion of email-address ownership. Web sites can use this mechanism to register users on their first visit and log them back in on their subsequent visits. The trust path for these assertions of email-address ownership is designed to be federated and decentralized: individual domains can certify their own users. A fallback secondary authentication mechanism is defined to bootstrap the protocol for domains that do not yet support it.
+
This specification, BrowserID, defines a mechanism for websites to request, from the user via her user-agent, a signed assertion of email-address ownership. Web sites can use this mechanism to register users on their first visit and log them back in on their subsequent visits. The trust path for these assertions of email-address ownership is designed to be federated and decentralized: individual domains can certify their own users. A fallback secondary authentication mechanism is proposed to bootstrap the protocol for domains that do not yet support it.
  
 
== Terms ==
 
== Terms ==
Line 139: Line 131:
 
where each cert and the identity assertion are base64url-encoded data structures, as defined above.
 
where each cert and the identity assertion are base64url-encoded data structures, as defined above.
  
== Main Protocol Flow ==
+
== Web-Site Signin Flow ==
  
 
''This section is informative.''
 
''This section is informative.''
Line 147: Line 139:
 
* <tt>example.com</tt> presents a login button with a JavaScript click handler.
 
* <tt>example.com</tt> presents a login button with a JavaScript click handler.
 
* when Alice clicks the login button, <tt>example.com</tt>'s click handler invokes
 
* when Alice clicks the login button, <tt>example.com</tt>'s click handler invokes
  navigator.id.get();
+
  navigator.id.request();
 
* Alice is presented with a user-agent dialog that lets her select which email to present to <tt>example.com</tt>.
 
* Alice is presented with a user-agent dialog that lets her select which email to present to <tt>example.com</tt>.
* If Alice chooses to cancel the transaction, a <tt>loginCancelled</tt> event is fired on the <tt>navigator.id</tt> object, which <tt>example.com</tt> can choose to listen for.
+
* If Alice chooses to cancel the transaction, a <tt>logincanceled</tt> event is fired on the <tt>navigator.id</tt> object, which <tt>example.com</tt> can choose to listen for.
 
* If Alice chooses to authenticate using one of her email addresses, a <tt>login</tt> event is fired on the <tt>navigator.id</tt> object, which <tt>example.com</tt> should listen for. The event's <tt>assertion</tt> property is filled with a Backed Identity Assertion.
 
* If Alice chooses to authenticate using one of her email addresses, a <tt>login</tt> event is fired on the <tt>navigator.id</tt> object, which <tt>example.com</tt> should listen for. The event's <tt>assertion</tt> property is filled with a Backed Identity Assertion.
 
* <tt>example.com</tt> should take this assertion and pass it back to its server. This can be accomplished with an AJAX request. For example, using jQuery:
 
* <tt>example.com</tt> should take this assertion and pass it back to its server. This can be accomplished with an AJAX request. For example, using jQuery:
  
 
  function gotAssertion(assertion) {
 
  function gotAssertion(assertion) {
   if (!assertion) {
+
   $.post("/verifyAssertion", {assertion: assertion}, afterVerifyAssertion);
    alert('you canceled login!');
+
  } else {
+
    $.post("/verifyAssertion", {assertion: assertion}, afterVerifyAssertion);
+
  }
+
 
  }
 
  }
  
 
This assertion is a Backed Identity Assertion, as defined above. We call it ''assertion'' here for simplicity, since the Relying Party typically need only pass this assertion to a verifier service without worrying about the specific assertion contents.
 
This assertion is a Backed Identity Assertion, as defined above. We call it ''assertion'' here for simplicity, since the Relying Party typically need only pass this assertion to a verifier service without worrying about the specific assertion contents.
 +
 +
== Identity Provisioning Flow ==
 +
 +
Consider Alice, a user of <tt>EyeDee.me</tt>, with email address <tt>alice@eyedee.me</tt>. Alice wishes to user her <tt>alice@eyedee.me</tt> identity to log into web sites that support the BrowserID protocol:
 +
 +
* Alice visits <tt>example.com</tt> and clicks "login."
 +
* In the BrowserID interface, Alice types her email address <tt>alice@eyedee.me</tt>.
 +
* The user-agent checks <tt>https://eyedee.me/.well-known/browserid</tt> and determines that <tt>eyedee.me</tt> supports BrowserID. From this configuration file it determines the provisioning and authentication URLs.
 +
* The user-agent loads, in an invisible IFRAME, the provisioning URL <tt>https://eyedee.me/browserid/provision.html</tt>, delivering to that URL any cookies that have previously been set.
 +
* The provisioning URL communicates with its server to determine if Alice is properly authenticated and, if so, triggers key generation within the user agent, obtains the public key, signs it, and registers the resulting certificate with the user agent:
 +
 +
// get parameters of provisioning
 +
navigator.id.beginProvisioning(function(email, cert_duration) {
 +
 +
    // ... check if the current user is authenticated as 'email' ...
 +
    if (notAuthenticated()) {
 +
        navigator.id.raiseProvisioningFailure("user isn't authenticated");
 +
        return;
 +
    }
 +
 +
    // request a keypair be generated by browserid and get the public key
 +
    navigator.id.genKeyPair(function(pubkey) {
 +
 +
        // ... interact with the server to sign the public key and get
 +
        // a certificate ...
 +
        var cert = someServerInteraction();
 +
 +
        // pass the certificate back to BrowserID and complete the
 +
        // provisioining process
 +
        navigator.id.registerCertificate(cert);
 +
    });
 +
});
 +
 +
 +
* If Alice is not properly authenticated, the user agent loads the authentication URL <tt>https://eyedee.me/browserid/authenticate.html</tt> in a dialog interface, where Alice can then proceed to log into <tt>EyeDee.me</tt> using whatever flow/method EyeDee.me wishes.
 +
 +
// set up UI
 +
navigator.id.beginAuthentication(function(email) {
 +
  // update UI to display the email address
 +
});
 +
 +
function onAuthentication() {
 +
  // check if the user authenticated successfully, if not, tell them
 +
  // it's a bad password. otherwise..
 +
  navigator.id.completeAuthentication();
 +
}
 +
 +
function onCancel() {
 +
  navigator.id.cancelAuthentication();
 +
}
 +
 +
Once this is successfully completed, the user-agent returns to the BrowserID user-interface, and attempts to load the provisioning URL as in the previous step.
 +
* Once a certificate for <tt>alice@eyedee.me</tt> is installed, the user-agent completes the login to <tt>example.com</tt> by creating an assertion and delivering it to <tt>example.com</tt> as in the Main Protocol Flow above.
 +
 +
By the end of this flow, Alice has obtained, within her user-agent, a certificate for her email address issued directly by her email address's domain.
  
 
== User-Agent Compliance ==
 
== User-Agent Compliance ==
 +
''This section is normative.''
  
The User-Agent is critical for Verified Email Protocol support. Here, we define, normatively, the API that user agents MUST implement, including specific behaviors in response to these API calls. Relying Parties and Identity Providers can safely skip this section.
+
The User-Agent plays an important role in BrowserID support. Here, we define, normatively, the API that user agents MUST implement, including specific behaviors in response to these API calls. Relying Parties and Identity Providers can safely skip this section.
  
=== API ===
+
A compliant BrowserID User-Agent must implement the <tt>navigator.id</tt> object, which serves both for issuing assertions and exposing a provisioning flow to identity providers.
  
A compliant VEP User-Agent must implement all <tt>navigator.id</tt> API calls as described here:
+
=== Issuing Assertions ===
  
<tt>navigator.id.getVerifiedEmail(object options, function callback);</tt>
+
The User Agent MUST offer the following API call:
  
The Relying Party MAY call the navigator.id.getVerifiedEmail method when it wishes to request that the User Agent generate an identity assertion as soon as it can. The User Agent SHOULD immediately seek to generate an Identity Assertion, prompting the user if it deems it necessary, and call the provided callback with an identity assertion or null in case the user chooses not to log in.
+
<tt>navigator.id.request(object options);</tt>
  
FIXME: should we provide error information if it's not just a user cancel?
+
The Relying Party MAY call the navigator.id.request method when it wishes to request that the User Agent generate an identity assertion as soon as it can. When this happens, the User Agent SHOULD pursue the following actions:
 +
 
 +
# Establish the origin of the requesting site (including scheme and non-standard port).
 +
# Check local BrowserID store for known identities that have been successfully used previously.
 +
# Present the list of known identities. The User Agent MAY suggest a preferred identity out of that list based on heuristics or other internal state, e.g. the email last used on that site.
 +
# When the user selects an Identity:
 +
## check that the associated certificate is still valid. If not, initiate a provisioning workflow for that Identity, then continue once it returns successfully.
 +
## generate an Identity Assertion using the requesting site's origin as audience and the current time. Bundle with the associated certificate to create a Backed Identity Assertion, and fire a <tt>login</tt> event on the <tt>navigator.id</tt> object with a serialization of the Backed Identity Assertion in the <tt>assertion</tt> field of the event, then terminate the login workflow.
 +
# If no Identities are known, or if the user wishes to use a new Identity, the User Agent should prompt the user for this new identity and use it to initiate a Provisioning workflow (see below). Once provisioning has completed, the User Agent SHOULD present the updated list of identities to the user.
 +
# If, at any point, the user cancels the login process, fire a <tt>logincanceled</tt> event on the <tt>navigator.id</tt> object and terminate the login workflow.
 +
 
 +
By the end of the process, the User Agent MUST fire one of two events on the <tt>navigator.id</tt> object:
 +
 
 +
* A <tt>loginCancelled</tt> event if the user chose not to log in.
 +
 
 +
* A <tt>login</tt> event if the user chose to log in. This event MUST include the Backed Identity Assertion in the <tt>assertion</tt> property.
 +
 
 +
XXX: should we provide error information if it's not just a user cancel?
 +
 
 +
=== Provisioning ===
 +
 
 +
The User Agent should support a provisioning workflow when a user wants to authenticate with a new email address. A provisioning workflow is initiated with some context:
 +
 
 +
* the email address being provisioned
 +
* information about the security status of the session (user's own computer, shared computer, public computer, ...)
 +
* whether the authentication workflow has been invoked yet (initially <tt>false</tt>).
 +
 
 +
During a provisioning action, the User Agent MUST support the following API calls:
  
 
<tt>navigator.id.beginProvisioning(object callback)</tt>
 
<tt>navigator.id.beginProvisioning(object callback)</tt>
  
The callback function SHOULD accept parameters <tt>email</tt> and <tt>cert_duration_s</tt>.
+
The User Agent SHOULD expect the callback function to accept parameters <tt>email</tt> and <tt>cert_duration_s</tt>.
 +
 
 +
In response to this call, the User Agent should invoke the callback with parameters based on the provisioning context. The <tt>email</tt> parameter MUST be the email address which the user-agent is attempting to provision. The <tt>cert_duration_s</tt> parameter should be the requested validity duration for the certificate, which the User Agent SHOULD determine based on the security level of the session. For example, public computers should have very short certificate validity.
  
 
<tt>navigator.id.genKeyPair(object callback);</tt>
 
<tt>navigator.id.genKeyPair(object callback);</tt>
  
The callback function SHOULD accept parameter <tt>pubkey</tt>, a serialized public-key string as per the above public-key spec.
+
The User Agent SHOULD expect the callback to accept parameter <tt>pubkey</tt>, a serialized public-key string as per the above public-key spec.
 +
 
 +
In response to this call, the User Agent MUST generate a fresh keypair associated with the email address for this provisioning context. The secret key should be stored internally, and the <tt>callback</tt> should be invoked with the serialized public-key as sole argument.
  
 
<tt>navigator.id.registerCertificate(certificate);</tt>
 
<tt>navigator.id.registerCertificate(certificate);</tt>
  
The certificate parameter MUST be a valid serialized certificate, as per the above spec. The trust root for this certificate SHOULD comply with the characteristics described in the "Acceptable Trust Paths" section below.
+
The User Agent SHOULD expect the certificate to be a valid serialized certificate, as per the above spec. The User Agent SHOULD expect the trust root for this certificate to comply with the characteristics described in the "Acceptable Trust Paths" section.
 +
 
 +
The User Agent MUST associate this certificate with the email address for this provisioning context and store this association internally for later issuance of Backed Identity Assertions.
  
 
<tt>navigator.id.raiseProvisioningFailure(string reason);</tt>
 
<tt>navigator.id.raiseProvisioningFailure(string reason);</tt>
  
The reason parameter MUST be a string that can be reported to the user regarding the reason why a certificate failed to be provisioned.
+
The User Agent MUST interrupt this provisioning workflow.
  
WebIDL:
+
If the context indicates that the authentication workflow has already been invoked, then the User Agent SHOULD return from this workflow indicating failure to authenticate the user.
 +
 
 +
If the context indicates that the authentication workflow has NOT already been invoked, then the User Agent SHOULD begin the Authentication Workflow (described below).
 +
 
 +
==== WebIDL ====
  
 
  module navigator {
 
  module navigator {
Line 199: Line 280:
 
         void beginProvisioning(object callback);
 
         void beginProvisioning(object callback);
 
         void genKeyPair(string email, object callback);
 
         void genKeyPair(string email, object callback);
         void registerCertificate(string certificate, string updateURL);
+
         void registerCertificate(string certificate);
 
         void raiseProvisioningFailure(string reason);
 
         void raiseProvisioningFailure(string reason);
 
     }
 
     }
 
  };
 
  };
  
 +
=== Authenticating ===
  
To process a request for identity registration from a web page, a User-Agent MUST:
+
The User Agent MUST support an authentication workflow when a user wants to certify a new email address but has failed the provisioning workflow. An authentication workflow is initiated with some context:
  
# Create, if it has not already done so, a local data store that will persist beyond the current page view, keyed on email identity.
+
* the email address which requires authentication
# Check the local data store for whether a certificate for the email address already exists and is valid. If so, the User-Agent SHOULD NOT proceed with key generation, and instead immediately call the provided callback to registerVerifiedEmail with a ''null'' argument.
+
# If no certificate already exists, the User-Agent MAY notify the user that a new email identity is being registered with the User-Agent. If the email identity has a domain that is different from the Identity Authority, the User-Agent SHOULD notify the user and seek confirmation.
+
# Produce an asymmetric keypair compatible with the JSON Web Key specification [JWK] and store it in the local data store.
+
# Return the public key to the JavaScript runtime of the web page through the provided callback.
+
# At a future point, when the registerVerifiedEmailCertificate function is called by a web page, the User Agent MUST verify that the public key in the Identity Certificate matches the already-stored keypair for the email identity in question. If it does not match, the User-Agent SHOULD reject the certificate and (do what?).
+
# Save the new certificate, as well as the refreshURL and errorURL arguments of the registerVerifiedEmailCertificate function.
+
  
=== Identity Assertion Generation ===
+
During an authentication workflow, the User Agent MUST support the following API calls:
  
To process a request for a verified email, a User-Agent MUST:
+
navigator.id.beginAuthentication(object callback);
# Reliably establish the full domain of the requesting site (including scheme and non-standard port).
+
# Check a local data store for previously established identity associations for the requesting site. If one or more associations are found, the User-Agent MAY ask the user for which identity to use, or automatically choose one based on some criteria (e.g., last-used).
+
# If no associations are found, the User-Agent SHOULD ask the user for what to do, by presenting a list of known email identities to choose from.
+
# If no email identities are known, the User-Agent MAY assist the user in any way it sees fit. [xxx ?]
+
# Verify the expiry date of the certificate associated with the identity of the previously-chosen association. If the certificate has expired, or would expire before the intended validity period of the assertion to be generated, the User-Agent MUST follow the steps in the CERTIFICATE REFRESH section of this specification.
+
# Create an Identity Assertion object for the chosen identity, scoped to the full domain of the requesting site (including scheme and non-standard port), and sign it with the private key associated with the chosen identity.
+
# Execute the navigator.id.onVerifiedEmail callback and provide the newly-created Identity Assertion as an argument.
+
  
=== Certificate Refresh ===
+
The User Agent SHOULD expect a callback function as parameter to this API call.
  
# To refresh a certificate, the User-Agent MUST fetch the resource located at the refresh URL provided by the Identity Authority in the registerVerifiedEmailCertificate for the certificate to be refreshed. The User-Agent SHOULD NOT display this resource to the user.
+
When this function is invoked, the User Agent MUST invoke the callback function, passing to it the context's email address as parameter.
# If the server returns with an error status when loaded (in the 4xx or 5xx range), certificate refresh has failed. The User-Agent SHOULD notify the user and load the error URL associated with the certificate at registration time. This resource SHOULD be visible to the user, who is expected to interact with the Identity Authority to resolve the problem.
+
 
# If the server returns with 2xx status, the loaded resource is expected to follow the steps under section 1.4 (Identity Registration) to sign new keys for the user.
+
navigator.id.completeAuthentication();
# The User Agent MUST maintain the resource loaded and operational for at least 30 seconds since last activity (network or JavaScript) to allow the Identity Authority to register multiple certificates if it wishes.
+
 
 +
When this function is invoked, the User Agent MUST return to its provisioning workflow, retrieving the appropriate context for that provisioning workflow, with the added flag <tt>authenticationPerformed = true</tt>.
 +
 
 +
navigator.id.raiseAuthenticationFailure(string reason);
 +
 
 +
When this function is invoked, the User Agent MUST return to its provisioning workflow and proceed with the failure case.
 +
 
 +
==== WebIDL ====
 +
 
 +
module navigator {
 +
    module id {
 +
        void beginAuthentication(object callback);
 +
        void completeAuthentication();
 +
        void raiseAuthenticationFailure(string reason);
 +
    }
 +
};
  
 
== Primary Authority Compliance ==
 
== Primary Authority Compliance ==
 +
''This section is normative.''
  
=== Declaring Support for Verified Email ===
+
A primary authority MUST:
 +
* declare support and parameters for BrowserID
 +
* provide a user-authentication web flow
 +
* provide a user-key-certification web flow
 +
 
 +
=== BrowserID Support Document ===
 +
 
 +
A BrowserID support document MUST be a well-formed JSON document with at least these three fields: <tt>public-key</tt>, <tt>authentication</tt>, and <tt>provisioning</tt>. The document MAY contain additional JSON fields.
 +
 
 +
The value of the <tt>public-key</tt> field MUST be a Public Key serialized as a JSON object, as defined above.
 +
 
 +
The value of the <tt>authentication</tt> field MUST be a relative reference to a URI, as defined by [https://tools.ietf.org/html/rfc3986 RFC3986].
 +
 
 +
The value of the <tt>provisioning</tt> field MUST also be a relative reference to a URI.
 +
 
 +
==== BrowserID Delegated Support Document ====
 +
 
 +
A BrowserID delegated-support document MUST be a well-formed JSON document with at least one field: <tt>authority</tt>. This field MUST be a domain name.
 +
 
 +
=== Declaring Support and Parameters for BrowserID ===
 +
 
 +
To declare support for BrowserID, a domain MUST publish either a BrowserID support document OR a BrowserID delegated-support document at a specific URI relative to the domain's SSL URI. The relative reference URI for this document is <tt>/.well-known/browserid</tt>, as per [https://tools.ietf.org/html/rfc5785 RFC5785]. The domain MAY choose to reference this BrowserID support document from a host-meta file (as per RFC5785).
 +
 
 +
The BrowserID support document (or delegated-support document) MUST be served with Content-Type <tt>application/json</tt>.
 +
 
 +
The BrowserID support document (or delegated-support document) MAY be served with cache headers to indicate longevity of the BrowserID support parameters.
 +
 
 +
=== Authenticating Users ===
 +
 
 +
A BrowserID-compliant domain MUST provide a user-authentication web flow starting at the URI referenced by the <tt>authentication</tt> field in its published BrowserID support document. The specifics of the user-authentication flow are up to the domain. The flow MAY use redirects to other pages, even other domains, to complete the user authentication process. The flow SHOULD NOT use <tt>window.open()</tt> or other techniques that target new windows/tabs.
 +
 
 +
The authentication flow MUST complete at a URI relative to the BrowserID-compliant domain. The completion page content MUST include a JavaScript call to either <tt>navigator.id.completeAuthentication()</tt> if authentication was successful or <tt>navigator.id.raiseAuthenticationFailure()</tt> if the use cancelled authentication.
  
 
=== Certifying Users ===
 
=== Certifying Users ===
 +
 +
A BrowserID-compliant domain MUST provider user-key-certification at the URI referenced by the <tt>provisioning</tt> field in its published BrowserID support document.
 +
 +
The domain SHOULD deliver HTML and JavaScript at that URI, which it can expect to be evaluated in a standard user-agent IFRAME.
 +
 +
The domain SHOULD determine, without any user-facing content, the user's state of authentication with the domain. The domain MAY use cookies or localStorage to make this determination.
 +
 +
The domain MUST call, in JavaScript:
 +
navigator.id.beginProvisioning(provisionEmailFunction);
 +
with <tt>provisionEmailFunction</tt> a function that accepts an email address as parameter.
 +
 +
Once the email address determined, the domain SHOULD check that the user is properly authenticated to use this email address. If she isn't, the domain SHOULD call
 +
navigator.id.raiseProvisioningFailure(explanation)
 +
with <tt>explanation</tt> a string explaining the failure. The domain SHOULD concludes all JavaScript activity after making this call.
 +
 +
You SHOULD use one of the following <tt>explanation</tt> codes:
 +
* <tt>user is not authenticated as target user</tt> - Indicates UA should show sign in screen again, due to an error
 +
 +
If the user is properly authenticated, the domain MUST call:
 +
navigator.id.genKeyPair(gotPublicKey);
 +
with <tt>gotPublicKey</tt> a function that accepts a JWK-string-formatted public-key.
 +
 +
The domain's JavaScript SHOULD then send this JWK string to the domain's backend server. The domain's backend server SHOULD certify this key along with the email address provided to its <tt>provisionEmailFunction</tt> function, and an expiration date at least 1 minutes in the future. The backend server SHOULD NOT issue a certificate valid longer than 24 hours. The domain's backend server SHOULD then deliver an Identity Certificate back to its JavaScript context. The domain's JavaScript MUST finally call:
 +
navigator.id.registerCertificate(certificate);
 +
with the Identity Certificate string.
  
 
== Assertion Verification ==
 
== Assertion Verification ==
  
Identity Assertions MUST NOT be verified in the client, in JavaScript or otherwise, since client runtimes may be altered to circumvent such verification. Instead, Identity Assertions SHOULD be sent to a trusted server for verification.
+
Backed Identity Assertions SHOULD NOT be verified in the client, in JavaScript or otherwise, since client runtimes may be altered to circumvent such verification. Instead, Backed Identity Assertions SHOULD be sent to a trusted server for verification.
  
To verify an Identity Assertion, a Relying Party MUST perform the following checks:
+
To verify a Backed Identity Assertion, a Relying Party SHOULD perform the following checks:
# If the valid-until date of the assertion is earlier than the current time, the assertion has expired and must be rejected.
+
# If the <tt>exp</tt> date of the assertion is earlier than the current time by more than a certain interval, the assertion has expired and must be rejected. A Relying Party MAY choose the length of that interval, though it is recommended that it be less than 5 minutes.
# If the nonce in the assertion has previously been received by the relying party, the assertion has been used and must be rejected.
+
# If the <tt>audience</tt> field of the assertion does not match the Relying Party's origin (including scheme and optional non-standard port), reject the assertion. A domain that includes the standard port, of 80 for HTTP and 443 for HTTPS, SHOULD be treated as equivalent to a domain that matches the protocol but does not include the port.  (XXX: Can we find an RFC that defines this equality test?)
# If the audience field of the assertion does not match the full domain (including scheme and optional non-standard port) of the page that requested the Identity Assertion, the assertion must be rejected. Note that implementations MUST include the scheme and non-standard port, if any, in the match check.  A domain that includes the standard port, of 80 for HTTP and 443 for HTTPS, MUST be treated as equivalent to a domain that matches the protocol but does not include the port.  (Can we find an RFC that defines this equality test?)
+
# If the Identity Assertion's signature does not verify against the public-key within the last Identity Certificate, reject the assertion.
# The signature over the assertion must be verified with the public key contained in the certificate.
+
# If there is more than one Identity Certificate, then reject the assertion unless each certificate after the first one is properly signed by the prior certificate's public key.
# The certificate must be verified using the issuer's public key. If the certificate contains an Issuer element, the certificate is secondary; in this case, the Relying Party must further decide whether the issuer is one that it trusts.
+
# If the first certificate (or only certificate when there is only one) is not properly signed by the expected issuer's public key, reject the assertion. The expected issuer is either the domain of the certified email address in the last certificate, or the issuer listed in the first certificate if the email-address domain does not support BrowserID.
 +
# If the expected issuer was designated by the certificate rather than discovered given the user's email address, then the issuer SHOULD be <tt>browserid.org</tt>, otherwise reject the assertion.
  
Note that a relying party may, at its discretion, use a verification service that performs these steps and returns a summary of results.  In that case, the verification service is acting as a relying party, and MUST perform all the checks described here.  In order to perform audience checking, the verification service must be told what audience to expect by the relying party.
+
Note that a relying party may, at its discretion, use a verification service that performs these steps and returns a summary of results.  In that case, the verification service MUST perform all the checks described here.  In order to perform audience checking, the verification service must be told what audience to expect by the relying party.
  
 
== Security Considerations ==
 
== Security Considerations ==

Revision as of 09:53, 24 February 2012

Contents

MediaWiki editor tip: If you aren't seeing numbered section headings in the body of this document, you can force them to appear by logging in and clicking the "My preferences" link, at left, and select "Auto-number headings"

DRAFT

IN PROGRESS

This document is in progress and is, in some respects, ahead of the actual BrowserID code. This document will be the single source of truth for BrowserID before 3/15/2012.

Overview

This specification, BrowserID, defines a mechanism for websites to request, from the user via her user-agent, a signed assertion of email-address ownership. Web sites can use this mechanism to register users on their first visit and log them back in on their subsequent visits. The trust path for these assertions of email-address ownership is designed to be federated and decentralized: individual domains can certify their own users. A fallback secondary authentication mechanism is proposed to bootstrap the protocol for domains that do not yet support it.

Terms

Identity
An email address controlled by the user.
Public Key
The public portion of an asymmetric cryptographic keypair used in a digital signature algorithm.
Identity Certificate
A digitally signed statement that binds a given public-key to a given Identity.
Primary Authority
A signer of Identity Certificates for identities that are directly within this authority's domain, e.g. example.com certifies *@example.com.
Secondary Authority
A signer of Identity Certificates for identities that are not directly within this authority's domain.
Audience/Relying Party
A system, typically a web site, that needs to verify an Identity.
Identity Assertion
A digitally signed statement that a login is requested to a particular relying party.
Backed Identity Assertion
An Identity Assertion combined with the requisite Identity Certificates that enable a Relying Party to fully verify the Identity Assertion.

Objects / Messages

BrowserID defines messages using the JOSE specifications for signing JSON-formatted objects.

Public Key

A BrowserID public key is a JSON object that includes fields:

  • alg the algorithm for which this key was generated, using JOSE taxonomy
  • additional fields specified by the algorithm, e.g. n and e for RSA public keys.

For example:

{
  "alg": "RS256",
  "n" : "4b3c34...",
  "e" : "93bc32...",
}

This data structure should move to JSON Web Keys.

Identity Certificate

An Identity Certificate is a JWT object with the following claims:

  • exp the expiration as per JWT
  • iss the domain of the issuer as per JWT
  • public-key the serialized public key as defined above
  • principal the principal being certified.

The principal is a JSON object that indicates the type of principal, e.g.

 {"email": "bob@example.com"}

or

 {"host": "intermediate.example.com"}

A complete JWT set of claims then looks like:

{
  "iss": "example.com",
  "exp": "1313971280961",
  "public-key": {
    "alg": "RS256",
    "n" : "4b3c34...",
    "e" : "93bc32...",
  },
  "principal": {
    "email": "john@example.com"
  }
}

Which, when signed, becomes a base64url-encoded data structure which looks like (with linebreaks and truncated values for for easier reading):

eyJhbGciOiJSUzI1NiJ9.
eyJpc3MiOiJicm93c2VyaWQub3JnIiwiZXhwIjoxM...
hv5wVN0HPINUZlLi4SJo9RzJhMU5_6XZsltYWODDD...

The JOSE spec currently does not specify a certificate format beyond JWS signatures. If it eventually does, we will consider moving to it.

Identity Assertion

An Identity Assertion is a JWT with the following claims:

  • exp for expiration
  • aud for the relying party (audience.)

An assertion might look like (with line breaks for readability):

eyJhbGciOiJSUzY0In0.
eyJleHAiOjEzMjAyODA1Nzk0MzcsImF1ZCI6Imh0dHA6Ly9sb2NhbGhvc3Q6MTAwMDEifQ.
JmEBqwOH_qzw6_EHsCRB-CeShGyQ2y0bpapARZ308_8uT6TCWrKBpB8L2bFnMb664lz1nGytkBXF-tTIzGCOjg

which is a JWT with header:

{"alg": "RS64"}

and a payload of:

{"exp":1320280579437,"aud":"http://localhost:10001"}

Backed Identity Assertion

A Backed Identity Assertion is a combination of an Identity Assertion and a singe sequence of Identity Certificates that verifiably tie the assertion to an issuing domain. Most often, a backed identity assertion is a single certificate tying a public-key to an Identity, signed by the domain, and an Identity Assertion signed by the just-certified public key.

A Backed Identity Assertion is:

<cert-1>~...<cert-n>~<identityAssertion>

where each cert and the identity assertion are base64url-encoded data structures, as defined above.

Web-Site Signin Flow

This section is informative.

Consider a web site, http://example.com, receiving a visit from a user. This web site wishes to obtain the user's verified email address using BrowserID. The user in question, for the purposes of this description, is Alice. Alice owns two email addresses, alice@homedomain and alice@workdomain.

  • example.com presents a login button with a JavaScript click handler.
  • when Alice clicks the login button, example.com's click handler invokes
navigator.id.request();
  • Alice is presented with a user-agent dialog that lets her select which email to present to example.com.
  • If Alice chooses to cancel the transaction, a logincanceled event is fired on the navigator.id object, which example.com can choose to listen for.
  • If Alice chooses to authenticate using one of her email addresses, a login event is fired on the navigator.id object, which example.com should listen for. The event's assertion property is filled with a Backed Identity Assertion.
  • example.com should take this assertion and pass it back to its server. This can be accomplished with an AJAX request. For example, using jQuery:
function gotAssertion(assertion) {
  $.post("/verifyAssertion", {assertion: assertion}, afterVerifyAssertion);
}

This assertion is a Backed Identity Assertion, as defined above. We call it assertion here for simplicity, since the Relying Party typically need only pass this assertion to a verifier service without worrying about the specific assertion contents.

Identity Provisioning Flow

Consider Alice, a user of EyeDee.me, with email address alice@eyedee.me. Alice wishes to user her alice@eyedee.me identity to log into web sites that support the BrowserID protocol:

  • Alice visits example.com and clicks "login."
  • In the BrowserID interface, Alice types her email address alice@eyedee.me.
  • The user-agent checks https://eyedee.me/.well-known/browserid and determines that eyedee.me supports BrowserID. From this configuration file it determines the provisioning and authentication URLs.
  • The user-agent loads, in an invisible IFRAME, the provisioning URL https://eyedee.me/browserid/provision.html, delivering to that URL any cookies that have previously been set.
  • The provisioning URL communicates with its server to determine if Alice is properly authenticated and, if so, triggers key generation within the user agent, obtains the public key, signs it, and registers the resulting certificate with the user agent:
// get parameters of provisioning
navigator.id.beginProvisioning(function(email, cert_duration) {

   // ... check if the current user is authenticated as 'email' ...
   if (notAuthenticated()) {
       navigator.id.raiseProvisioningFailure("user isn't authenticated");
       return;
   }

   // request a keypair be generated by browserid and get the public key
   navigator.id.genKeyPair(function(pubkey) {

       // ... interact with the server to sign the public key and get
       // a certificate ...
       var cert = someServerInteraction();

       // pass the certificate back to BrowserID and complete the
       // provisioining process
       navigator.id.registerCertificate(cert);
   });
});


  • If Alice is not properly authenticated, the user agent loads the authentication URL https://eyedee.me/browserid/authenticate.html in a dialog interface, where Alice can then proceed to log into EyeDee.me using whatever flow/method EyeDee.me wishes.
// set up UI
navigator.id.beginAuthentication(function(email) {
  // update UI to display the email address
});

function onAuthentication() {
  // check if the user authenticated successfully, if not, tell them
  // it's a bad password. otherwise..
  navigator.id.completeAuthentication();
}

function onCancel() {
  navigator.id.cancelAuthentication();
}

Once this is successfully completed, the user-agent returns to the BrowserID user-interface, and attempts to load the provisioning URL as in the previous step.

  • Once a certificate for alice@eyedee.me is installed, the user-agent completes the login to example.com by creating an assertion and delivering it to example.com as in the Main Protocol Flow above.

By the end of this flow, Alice has obtained, within her user-agent, a certificate for her email address issued directly by her email address's domain.

User-Agent Compliance

This section is normative.

The User-Agent plays an important role in BrowserID support. Here, we define, normatively, the API that user agents MUST implement, including specific behaviors in response to these API calls. Relying Parties and Identity Providers can safely skip this section.

A compliant BrowserID User-Agent must implement the navigator.id object, which serves both for issuing assertions and exposing a provisioning flow to identity providers.

Issuing Assertions

The User Agent MUST offer the following API call:

navigator.id.request(object options);

The Relying Party MAY call the navigator.id.request method when it wishes to request that the User Agent generate an identity assertion as soon as it can. When this happens, the User Agent SHOULD pursue the following actions:

  1. Establish the origin of the requesting site (including scheme and non-standard port).
  2. Check local BrowserID store for known identities that have been successfully used previously.
  3. Present the list of known identities. The User Agent MAY suggest a preferred identity out of that list based on heuristics or other internal state, e.g. the email last used on that site.
  4. When the user selects an Identity:
    1. check that the associated certificate is still valid. If not, initiate a provisioning workflow for that Identity, then continue once it returns successfully.
    2. generate an Identity Assertion using the requesting site's origin as audience and the current time. Bundle with the associated certificate to create a Backed Identity Assertion, and fire a login event on the navigator.id object with a serialization of the Backed Identity Assertion in the assertion field of the event, then terminate the login workflow.
  5. If no Identities are known, or if the user wishes to use a new Identity, the User Agent should prompt the user for this new identity and use it to initiate a Provisioning workflow (see below). Once provisioning has completed, the User Agent SHOULD present the updated list of identities to the user.
  6. If, at any point, the user cancels the login process, fire a logincanceled event on the navigator.id object and terminate the login workflow.

By the end of the process, the User Agent MUST fire one of two events on the navigator.id object:

  • A loginCancelled event if the user chose not to log in.
  • A login event if the user chose to log in. This event MUST include the Backed Identity Assertion in the assertion property.

XXX: should we provide error information if it's not just a user cancel?

Provisioning

The User Agent should support a provisioning workflow when a user wants to authenticate with a new email address. A provisioning workflow is initiated with some context:

  • the email address being provisioned
  • information about the security status of the session (user's own computer, shared computer, public computer, ...)
  • whether the authentication workflow has been invoked yet (initially false).

During a provisioning action, the User Agent MUST support the following API calls:

navigator.id.beginProvisioning(object callback)

The User Agent SHOULD expect the callback function to accept parameters email and cert_duration_s.

In response to this call, the User Agent should invoke the callback with parameters based on the provisioning context. The email parameter MUST be the email address which the user-agent is attempting to provision. The cert_duration_s parameter should be the requested validity duration for the certificate, which the User Agent SHOULD determine based on the security level of the session. For example, public computers should have very short certificate validity.

navigator.id.genKeyPair(object callback);

The User Agent SHOULD expect the callback to accept parameter pubkey, a serialized public-key string as per the above public-key spec.

In response to this call, the User Agent MUST generate a fresh keypair associated with the email address for this provisioning context. The secret key should be stored internally, and the callback should be invoked with the serialized public-key as sole argument.

navigator.id.registerCertificate(certificate);

The User Agent SHOULD expect the certificate to be a valid serialized certificate, as per the above spec. The User Agent SHOULD expect the trust root for this certificate to comply with the characteristics described in the "Acceptable Trust Paths" section.

The User Agent MUST associate this certificate with the email address for this provisioning context and store this association internally for later issuance of Backed Identity Assertions.

navigator.id.raiseProvisioningFailure(string reason);

The User Agent MUST interrupt this provisioning workflow.

If the context indicates that the authentication workflow has already been invoked, then the User Agent SHOULD return from this workflow indicating failure to authenticate the user.

If the context indicates that the authentication workflow has NOT already been invoked, then the User Agent SHOULD begin the Authentication Workflow (described below).

WebIDL

module navigator {
    module id {
        void beginProvisioning(object callback);
        void genKeyPair(string email, object callback);
        void registerCertificate(string certificate);
        void raiseProvisioningFailure(string reason);
    }
};

Authenticating

The User Agent MUST support an authentication workflow when a user wants to certify a new email address but has failed the provisioning workflow. An authentication workflow is initiated with some context:

  • the email address which requires authentication

During an authentication workflow, the User Agent MUST support the following API calls:

navigator.id.beginAuthentication(object callback);

The User Agent SHOULD expect a callback function as parameter to this API call.

When this function is invoked, the User Agent MUST invoke the callback function, passing to it the context's email address as parameter.

navigator.id.completeAuthentication();

When this function is invoked, the User Agent MUST return to its provisioning workflow, retrieving the appropriate context for that provisioning workflow, with the added flag authenticationPerformed = true.

navigator.id.raiseAuthenticationFailure(string reason);

When this function is invoked, the User Agent MUST return to its provisioning workflow and proceed with the failure case.

WebIDL

module navigator {
    module id {
        void beginAuthentication(object callback);
        void completeAuthentication();
        void raiseAuthenticationFailure(string reason);
    }
};

Primary Authority Compliance

This section is normative.

A primary authority MUST:

  • declare support and parameters for BrowserID
  • provide a user-authentication web flow
  • provide a user-key-certification web flow

BrowserID Support Document

A BrowserID support document MUST be a well-formed JSON document with at least these three fields: public-key, authentication, and provisioning. The document MAY contain additional JSON fields.

The value of the public-key field MUST be a Public Key serialized as a JSON object, as defined above.

The value of the authentication field MUST be a relative reference to a URI, as defined by RFC3986.

The value of the provisioning field MUST also be a relative reference to a URI.

BrowserID Delegated Support Document

A BrowserID delegated-support document MUST be a well-formed JSON document with at least one field: authority. This field MUST be a domain name.

Declaring Support and Parameters for BrowserID

To declare support for BrowserID, a domain MUST publish either a BrowserID support document OR a BrowserID delegated-support document at a specific URI relative to the domain's SSL URI. The relative reference URI for this document is /.well-known/browserid, as per RFC5785. The domain MAY choose to reference this BrowserID support document from a host-meta file (as per RFC5785).

The BrowserID support document (or delegated-support document) MUST be served with Content-Type application/json.

The BrowserID support document (or delegated-support document) MAY be served with cache headers to indicate longevity of the BrowserID support parameters.

Authenticating Users

A BrowserID-compliant domain MUST provide a user-authentication web flow starting at the URI referenced by the authentication field in its published BrowserID support document. The specifics of the user-authentication flow are up to the domain. The flow MAY use redirects to other pages, even other domains, to complete the user authentication process. The flow SHOULD NOT use window.open() or other techniques that target new windows/tabs.

The authentication flow MUST complete at a URI relative to the BrowserID-compliant domain. The completion page content MUST include a JavaScript call to either navigator.id.completeAuthentication() if authentication was successful or navigator.id.raiseAuthenticationFailure() if the use cancelled authentication.

Certifying Users

A BrowserID-compliant domain MUST provider user-key-certification at the URI referenced by the provisioning field in its published BrowserID support document.

The domain SHOULD deliver HTML and JavaScript at that URI, which it can expect to be evaluated in a standard user-agent IFRAME.

The domain SHOULD determine, without any user-facing content, the user's state of authentication with the domain. The domain MAY use cookies or localStorage to make this determination.

The domain MUST call, in JavaScript:

navigator.id.beginProvisioning(provisionEmailFunction);

with provisionEmailFunction a function that accepts an email address as parameter.

Once the email address determined, the domain SHOULD check that the user is properly authenticated to use this email address. If she isn't, the domain SHOULD call

navigator.id.raiseProvisioningFailure(explanation)

with explanation a string explaining the failure. The domain SHOULD concludes all JavaScript activity after making this call.

You SHOULD use one of the following explanation codes:

  • user is not authenticated as target user - Indicates UA should show sign in screen again, due to an error

If the user is properly authenticated, the domain MUST call:

navigator.id.genKeyPair(gotPublicKey);

with gotPublicKey a function that accepts a JWK-string-formatted public-key.

The domain's JavaScript SHOULD then send this JWK string to the domain's backend server. The domain's backend server SHOULD certify this key along with the email address provided to its provisionEmailFunction function, and an expiration date at least 1 minutes in the future. The backend server SHOULD NOT issue a certificate valid longer than 24 hours. The domain's backend server SHOULD then deliver an Identity Certificate back to its JavaScript context. The domain's JavaScript MUST finally call:

navigator.id.registerCertificate(certificate);

with the Identity Certificate string.

Assertion Verification

Backed Identity Assertions SHOULD NOT be verified in the client, in JavaScript or otherwise, since client runtimes may be altered to circumvent such verification. Instead, Backed Identity Assertions SHOULD be sent to a trusted server for verification.

To verify a Backed Identity Assertion, a Relying Party SHOULD perform the following checks:

  1. If the exp date of the assertion is earlier than the current time by more than a certain interval, the assertion has expired and must be rejected. A Relying Party MAY choose the length of that interval, though it is recommended that it be less than 5 minutes.
  2. If the audience field of the assertion does not match the Relying Party's origin (including scheme and optional non-standard port), reject the assertion. A domain that includes the standard port, of 80 for HTTP and 443 for HTTPS, SHOULD be treated as equivalent to a domain that matches the protocol but does not include the port. (XXX: Can we find an RFC that defines this equality test?)
  3. If the Identity Assertion's signature does not verify against the public-key within the last Identity Certificate, reject the assertion.
  4. If there is more than one Identity Certificate, then reject the assertion unless each certificate after the first one is properly signed by the prior certificate's public key.
  5. If the first certificate (or only certificate when there is only one) is not properly signed by the expected issuer's public key, reject the assertion. The expected issuer is either the domain of the certified email address in the last certificate, or the issuer listed in the first certificate if the email-address domain does not support BrowserID.
  6. If the expected issuer was designated by the certificate rather than discovered given the user's email address, then the issuer SHOULD be browserid.org, otherwise reject the assertion.

Note that a relying party may, at its discretion, use a verification service that performs these steps and returns a summary of results. In that case, the verification service MUST perform all the checks described here. In order to perform audience checking, the verification service must be told what audience to expect by the relying party.

Security Considerations

things to write about:

  • certificate validity period
  • UAs reusing a key to get a new certificate
  • timing attacks
  • javascript implementations, good RNGs

References