THIS PRELIMINARY SPECIFICATION IS SUBJECT TO
CHANGE AT ANY TIME (AND IT HAS BEEN!!)
At this time it is being published for comment only. Please DO NOT RELY
upon it until this notice has been removed. (Which should be soon!)
SQRL QR code/hyperlink URL format
SQRL URLs may be encoded into graphical QR codes to enable multifactor cross-device authentication, or embedded into standard HTML links to enable local, same-device SQRL authentication. To afford maximum server-side design freedom, the SQRL URL format has minimal requirements:
- Scheme: The SQRL URL scheme is either “sqrl” or “qrl”. The strongly preferred use of “sqrl” as the SQRL URL's scheme signals to the SQRL client that the web server supports standard encrypted and authenticated SSL/TLS connections and has a certificate for the indicated domain. Unless a standard colon-delimited port override is provided, the SQRL client will connect to the IP for the indicated domain at standard HTTPS port 443 and issue a standard HTTP GET query.
If a host web server does not support SSL/TLS connections, it may signal this to the SQRL client by using the “qrl” scheme. This drops the leading “s” to signal that the SQRL client should issue its user authentication query over an unsecured HTTP connection. In this case, unless a standard colon-delimited port override is provided, the SQRL client will connect to the IP for the indicated domain at standard HTTP port 80 and issue a standard HTTP GET query.
- Domain: As usual, the domain portion of the URL specifies the DNS domain to be looked up to determine the host web server's connection IP address. This is also the same string that is HMAC hashed to create the user's site-specific private key ‑ unless the URL's query tail contains a “d” (domain depth) modifier described below.
- Query Separator & Query: The query data begins after the query separator (?) question mark character. To protect against various sorts of replay and prediction attacks, the only required query data is a cryptographically strong unpredictable and opaque token. This has been previously referred to with the generic term “nonce.” However, due to its specific unpredictability and possible reversibility requirements (more than simply a number used once) this more complete formal specification will use the term “nut.”
Its precise role will vary based upon the server's implementation needs. It might be the result of a strong one-way hash function or a strong reversible symmetric cipher. But since it is publicly exposed in the SQRL link URL, it must at least have the property of cryptographically strong unpredictability:
- The “Web Server Behavior” section below will further discuss the recommended ways this “nut” value can be developed and used by the hosting web server.
- Any OTHER server session token: This will discussed below, under “Web Server Behavior,
” but it's important enough to be mentioned here. Due to the fact that login session-state information is being placed onto a web page where it is then taken up by an SQRL authenticator, the value of any other token the web server might use for session identification must also be completely unpredictable. If, for example, a simple session number counter were used, an attacker might examine the SQRL link, predict a future session ID, then trick the user into signing a modified SQRL link for the attacker to use in impersonating the user. Any session tokens should therefore be generated by a cryptographically strong cipher under a secret key or a strong secretly salted hash function.
- Portion of URL to be hashed and signed: Except as modified by the presence of the optional “d” parameter (see following item) the SQRL authenticator securely hashes (with a secretly keyed HMAC function) the entire DNS domain name contained in the SQRL link URL.
After the authenticator has appended all of its own parameters (except the signature), the entire URL is signed from the start of the DNS domain name through the end of the URL . . . then the signature is appended.
- The optional “d” parameter:
- As shown in the diagram above, a SQRL URL may optionally contain a “d=value” parameter pair where “d” stands for domain or depth. If present, it will cause the SQRL client to “include to the right” the number of characters specified by the parameter up to the first “?” or the end of the URL (whichever occurs first). This optional feature allows websites which support separate user accounts defined at the start of the resource path (such as GitHub) to inform the SQRL client of this by specifying on a sub-site by sub-site basis, how many characters to the right of the end of the domain name should be included in the SQRL's HMAC key hashing.
Note that since the first character after the domain name is the domain name “/” path separator, “d=1” would have no useful effect, would always be erroneous, and should be ignored. Similarly, if the value following the “d=” is not a simple number, or if it specifies a character count that would extend past the end of the path, the SQRL client should consider it invalid and silently ignore it (under the assumption that it's a parameter used by the host web server itself for some other purpose.).
Characters versus bytes: To eliminate any ambiguity in the definition and use of the “d” parameter's value, if multi-byte characters are present in the path, each byte of any multi-byte characters should be counted individually in setting the “d” parameter's value. SQRL authentication clients which are HMAC hashing the URL will ignore multi-byte semantics and use the “d” parameter as a byte count.
- Anything else in the SQRL link: The web server is free to add and name any additional arguments that it chooses to the SQRL link URL. It should avoid using “d” as an argument, and should not use any parameter names which collide with those which will be appended by the SQRL authentication process.
SQRL authentication query format
In the odd and somewhat contrived operation of the web, a web client may use a “GET” query to send a web server data by asking the server for a standard web resource, where the data it wishes to send is appended to the end of the resource's name. This is the so-called “query tail”. A web client can also use a “POST” query to send additional data which might be too lengthy to fit into a URL, might be binary data, or otherwise unsuitable for a URL's environment. Since the SQRL login link URL received from the web server is augmented with additional data, then signed, we use the POST verb's natural division of data where the SQRL arguments to be signed along with the web server's URL are appended to the URL, and the signature of the resulting compound URL is provided in the body of the POST submission.
The URL's parameters are standard HTTP form-urlencoded parameters where name=value pairs are separated by ‘&’ characters:
The use of standardized HTTP GET and POST query syntax allows existing web query parsing, interpretation tools and libraries to be used without modification.
How the SQRL query string is formed:
Starting with the SQRL link URL contained in an optically scanned QR code or in a standard HTML link:
- The client begins by copying the entire SQRL link URL into a text assembly buffer. The SQRL client parameters and public identity key will add approximately 80 characters to the final URL length, though more if more option values are added in the future and present. The exact size needed can be easily calculated beforehand. At this point, the URL being assembled would look like this, with whatever original query parameters were part of the web server's provided SQRL link:
- Next, as shown below, two or three SQRL client parameters are appended to the URL which is growing in the assembly buffer. (The “sqrlopt” parameter and value only need to be present if an option is specified; otherwise it may be omitted.) The details of each parameter are outlined below. :
- This string, exactly as it now sits in the assembly buffer, is what the SQRL client signs and the host web server later reassembles and verifies. So, we pass this string through the Ed25519 signature system to obtain the signature for the entire URL.
- When the SQRL client's POST query is submitted to the web server:
- The sqrl:// or qrl:// scheme and separator characters are discarded. The web server knows what they should be, so it will restore them before verifying the query's signature.
- The DNS domain name obtained from the original SQRL link, which will be used to lookup the web server host's IP address, becomes the value of the query's Host: header.
- The balance of the contents of the URL assembly buffer is used (without the domain name) beginning with the first (‘/’) forward slash as the URL for the query.
- The signature obtained from the signing is used as the body of the post following the same URL-style name=value format:
ASCII Encoding of Binary Data
The sqrlkey and sqrlsig values are generated as a pair of binary character arrays of 256 and 512 bits respectively. In order for the sqrlkey to exist in a URL, its alphabet must be converted from 8-bit bytes into a “safe” subset of the ASCII character set. For ease of development, comparison, cutting and pasting sample data, etc., we also convert the 512 bits of sqrlsig data, even though it could be transported without conversion in the body of an HTTP POST.
To perform this conversion, we employ a widely available variation of the standard base64 encoding known as “
base64url” as defined in the
Base Data Encodings RFC #4648. The “base64url” encoding replaces the URL-hostile ‘
+’ and ‘
/’ characters, which are typically used as the last two non-alphanumeric symbols in the encoding alphabet, with the URL-friendly characters ‘
-’ and ‘
_’ respectively. However
. . .
Trailing “=” characters must be trimmed from
the end before the encoded strings are used.
Base64 encoding converts 8-bit bytes into a 6-bit character set. The least common multiple (LCM) of 8 and 6 is 24. Therefore, some base64 converters perform their conversions by taking multiples of three 8-bit binary source bytes (24-bits) to produce four 6-bit characters (24-bits). The trouble with this is that the source data length may not be an even multiple of 3 bytes (and none of ours are). Encoders resolve this (annoyingly) by appending one or two null (all zero) bytes to fill out the final “group of three” source bytes. Such converters also insist upon always emitting full sets of four encoded characters . . . even if doing so means that they must pad the output with “=” equals sign characters (since they have no real source data to go with those padding characters).
The “=” equals sign is NOT a URL-safe character because it is reserved to join URL parameter names and values. Therefore, the SQRL standard requires that any trailing “=” characters be trimmed and removed from the end of all base64url converted strings.
Our sqrlkey public identity key string will always end in one (“=”) equals sign, and our sqrlsig signature will end with two (“==”) equals signs. They
must be removed. The same care should be taken by the server with the encoding and subsequent decoding of its “nut” value included in the SQRL link URL.

Note that when the encoding process is reversed to decode and return the ASCII back to binary, some base64url decoders will expect to encounter the original (“=”) equals signs. So, to be safe, the web server that decodes these strings should append one (“=”) equals sign to the sqrlkey value and two (“==”) equals signs to the sqrlsig.
- Here is a sample, fully-expanded, query showing the server-provided “nut” parameter, the SQRL client's “sqrlver”, “sqrlopt”, and “sqrlkey” name=value pairs, with all binary-to-base64url values properly sized:
- Here is a sample of the POST body data containing the base64url-converted signature. Note that we continue to use the name=value syntax. This will allow us to add additional data to the POST body if that should be needed in the future.
- In the samples above, you'll note that none of either the argument names or values are enclosed in single or doubt quotes. The protocol has no need for quote delimiters, since ‘=’ and ‘&’ and end-of-buffer provide unambiguous name and value delimiters . . . and, as explained above, end-of-string “=”-padding is removed from all base64url-encoded strings.
SQRL Client Parameters
sqrlver
This SQRL query parameter specifies the version of protocol the client is currently using. This single monotonic integer implies the protocol described here with the use of Bernstein's Ed25519 elliptic curve cryptosystem. Any changes to this baseline will be conveyed buy a version other than “1”.
Therefore, as this system launches, the only SQRL version currently defined is 1. Therefore the string SQRL clients should emit, and the string web servers should expect, is exactly this:
sqrlver=1
sqrlopt
Although only a single SQRL option is currently defined, the specification defines a list of comma-separated keyword tokens of the form: sqrlopt=OptionOne,OptionTwo,OptionThree. So client-side generation and serve-side parsing might wish to plan for multiple comma-separated options.
If no options are required the SQRL client may entirely omit “sqrlopt=” from the query string. In other words, the lack of any “sqrlopt=” is valid and means “no options requested”.
Options presently defined are:
- enforce (Enforce identical login and authentication IP addresses.)
This option is extremely useful for detecting and blocking phishing attacks in any situation where the SQRL authenticating client's IP address is expected to be the same as the machine that received the SQRL link URL. In other words, for “same-machine” login. Therefore, this would apply for desktops, laptops, tablets and phones where the user is logging in with the same machine they are authenticating on. Conversely, it would generally not apply in cross-machine logins where the two devices have differing public IP addresses. However, many smartphone users use their residential wireless networks while at home, so even in that cross-machine login, their IPs would be expected to be identical.
When this optional parameter is added by the SQRL client and received by the web server, the web server MUST fail the authentication attempt if the IP address to which it securely sent the original SQRL link URL does not match the IP address from which it received the login authentication query.
The web server must return an error indicating that the IP enforcement failed and that the login query was discarded. However, since the SQRL client's user may choose to retry the login without the enforce option, the web server should not discard any pre-login session state so that it will be able to authenticate and login the user if (a) an identical IP address is then used or (b) the client removes the enforcement request option.
sqrlkey
The value for the sqrlkey parameter is generated by the Ed29915 elliptic curve public key signing cryptosystem. It is initially a 256-bit, 32-byte array, which is then encoded using a base64url function into a string of exactly 44 ASCII characters. After its single trailing (“=”) equals sign is removed, the resulting 43-character string becomes the value for the sqrlkey parameter.
sqrlsig
This parameter is not transported in the SQRL client's query URL, but rather in the body of its POST data. For that reason, conversion to ASCII is not necessary, but for clarity and consistency, binary values are treated uniformly within this system. And the use of ASCII-oriented name=value syntax, although also not technically necessary, allows standard POST parameter parsing libraries to be used and it allows us to add additional parameters in the future.
As with the preceding sqrlkey value, the value for the sqrlsig parameter is generated by the Ed29915 elliptic curve public key signing cryptosystem. It is initially a 512-bit, 64-byte array, which is then encoded using a base64url function creating a string of exactly 88 ASCII characters. After its two trailing (“==”) equals signs are removed, the resulting 86-character string becomes the value for the sqrlsig parameter which forms the body of the POST query. (Depending upon the library being used, this may either be added automatically as a parameter to a “SendPOST” function of some sort, or as the query data exists on the wire, by adding one blank line following the POST's query headers, then appending the sqrlsig string.)
Web Server Behavior
Support for the SQRL protocol generally imposes minimal requirements and burdens upon web servers. When signature verification is performed by compiled code, many hundreds of thousands of verifications can be performed per second per core on any contemporary processor. The elliptic curve public key cryptography chosen for use with SQRL (Bernstein's Ed25519) has been optimized for high performance, and is far less burdensome than traditional RSA-style “products of primes” cryptography. Elliptic curve crypto is faster because it uses much shorter keys which, in turn, are as safe or safer than longer RSA keys because the discrete logarithm problem used by elliptic curve crypto is believed to be much more difficult to solve, for a given key length, than the RSA prime factorization problem. Thus, faster-to-use shorter ECC keys deliver the same strength as longer slower-to-use RSA keys.
Although SQRL's cryptosystem design is believed to be unassailable, various man-in-the-middle spoofing-style attacks are possible if simple precautions and checks are not performed by the web server. The guidelines below will assist the developer in implementing an SQRL system to deliver the strongest web server authentication available.
Preparing the SQRL link URL for stateful or stateless login
Before a web server displays a visitor login page containing an SQRL QR code and link, it may establish some pre-login state information which is retained for some length of time (until the login page ages and expires), or it might not establish any pre-login state until a user submits their login form data or uses the SQRL code to identify and authenticate themselves. SQRL is adaptable to either scheme.
As was mentioned briefly above, SQRL QR code and link data is inherently exposed on the web site's login page. To protect itself from login-state-guess attacks, and to guarantee that SQRL clients have unique SQRL links to sign, SQRL-login websites must provide a cryptographic-strength unpredictable and never-repeating “nut” to assure that every link is unique. Depending upon whether the server's logic is stateless or stateful, the nut's value may be derived from a one-way cryptographic hash function such as SHA-1, or from a two-way reversible cryptographic cipher such as AES.
A server that creates some pre-login state when the user asks for a login page and an accompanying SQRL link URL is generated might simply obtain some random noise from the local system, hash it through SHA-1 to destroy any structure it might have. This 160-bit token would then be stored in the server's pre-login state and perhaps added to a list or otherwise made indexable so that it can be located when the matching SQRL query arrives. Since SQRL web servers must compare the initial login request IP to the authenticating IP, when both connections are over SSL, the pre-login state must also save the login requesting IP. That 160-bit data would then be passed through a base64url function to convert the resulting 160-bits into URL-friendly ASCII. (Remember to remove any trailing (“=”) equal signs padding the end of the string.) This ASCII would then form the server's “nut” added to the SQRL link URL after the “?” in order to render a unique link.
A server that does NOT create pre-login state will likely wish to encrypt some necessary connection IP and sanity-checking parameters into the server's nut:
32 bits: user's connection IP address if secured, 0.0.0.0 if non-secured.
32 bits: UNIX-time timestamp incrementing once per second.
32 bits: up-counter incremented once for every SQRL link generated.
32 bits: pseudo-random noise from system source.
----------
128 bits - AES encryption block size
|
Suggested data that might be encrypted in the server's nut.
- Connection IP: To help prevent the most common phishing and man-in-the-middle (MITM) attacks, the web server must compare the IP to which the SQRL QR code and link is sent with the IP of the machine that submits the identity authenticating query. Since this is a stateless login, the initial user IP must be enclosed in the server's nut. Since ISP caching proxies may mask their customer's true IP addresses, the IP address should only be stored if the login page and SQRL link are sent over a cache-bypassing SSL connection. Hopefully, login page content will be delivered over SSL connections. An IP address of 0.0.0.0 can be used to indicate that the user's login requesting IP address is unknown when the web server is not using SSL to display the login page contents.
- UNIX-time Timestamp: Including the readily available one-increment-per-second UNIX time both provides a steadily changing value and creates a simple timestamp that can be used to “sanity-check” the returning query. A very stale authentication query can be rejected, with the user asked to refresh their login page. And any alteration of the encrypted nut's value, when decrypted, will almost certainly result in impossible times in the future or far in the past which can be easily detected and discarded.
- Up Counter: A simple 32-bit up-counter that can be allowed to wrap, and/or can restart at zero after a reboot, is a low-cost means for guaranteeing that even if multiple login pages are requested and delivered in rapid succession, each will have a differing count value. This value can also be used as a quick sanity-check since returning decrypted values should never be greater than the counter, nor should they be too much smaller that the counter's current value. Anything hacking attack that alters any of the encrypted nut's 128-bits would likely result in a wildly incorrect count value after decryption, this quickly failing any sanity checking.
- Some Pseudo-Random Noise Since the previous three components are somewhat predictable, and could at least partially be under an attacker's control, something unpredictable and completely uncontrollable, such as entropy generated by the local machine, should also be added to the pre-encrypted nut. Although it cannot be verified after decryption, its presence within the nut renders any sort of attack on the nut's encryption (which was already far beyond unlikely) virtually impossible.
The parameters described above are intended to serve as suggestions and guidelines only. They are certainly not hard and fast rules. Anything a web application might need can be accommodated by altering or expanding upon the concepts above.
Once a 128-bit block of parameters have been assembled, a 128-bit block cipher, such as AES, can be used to reversibly encrypt the block to yield the SQRL link's directly related, but indecipherable, 128-bit nut. The AES key could be made static or it could be chosen at random after each server boot, but it should remain secret and internal to the web server. The 128-bit binary nut should then be converted to ASCII using the base64url encoder and the two trailing (“==”) equal signs should be removed before it is added to the SQRL link URL, and later appended before the returned nut is decoded back into binary by a base64url decoder.
Once the ASCIIized value for the link's nut is generated, the value for the optional path-extending “d” parameter, if any, should be determined, and a SQRL login link can be created. The link URL could be fed into a QR code generator to create a PNG or GIF (not JPG) format QR code image. That image should be wrapped in a standard HTML clickable <a href="url">qrcode.png</a> HREF tag so that smartphones can optically scan the QR code for cross-device authenticated login, while users of smartphones, tablets, laptops and desktops can tap or click on the image to perform the same function.
On-the-fly generation of QR codes
An alternative to feeding the URL into a QR code generator, then linking to the resulting image file, would be to embed the entire link URL into the name of the QR code PNG image and arrange to have the web server generate and return the QR code image on-the-fly, from memory, in direct response to the user's web browser request for the image:
<img src="/sqrlcode/{url-encoded sqrl link}.png" alt="Click to Login" />
This is the approach I have taken for the generation of all charts and graphs throughout GRC's website. Examples are the
DNS Spoofability Test (click the link at the bottom of the page to run the test and view the charts) and the
Web Browser Cookie Statistics page. At no time do any of those images reside on disk. They are created in memory, served from memory, then immediately discarded once sent. The same can be done with QR code images.
Handling the SQRL client's authentication query
<///// Still working on this part . . . /////>