This site is the archived OWASP Foundation Wiki and is no longer accepting Account Requests.
To view the new OWASP Foundation website, please visit https://owasp.org

Difference between revisions of "Certificate and Public Key Pinning"

From OWASP
Jump to: navigation, search
m (Corrected Code-Formating)
 
(34 intermediate revisions by 15 users not shown)
Line 1: Line 1:
  
[[Certificate and Public Key Pinning]] is a technical guide to implementing certificate and public key pinning as discussed at the ''[https://www.owasp.org/index.php/Virginia Virginia chapter's]'' presentation [[Media:Securing-Wireless-Channels-in-the-Mobile-Space.ppt|Securing Wireless Channels in the Mobile Space]]. This guide is focused on providing clear, simple, actionable guidance for securing the channel in a hostile environment where actors could be malicious and the conference of trust a liability. Additional presentation material included [[Media:pubkey-pin-supplement.pdf|supplement with code excerpts]], [[Media:pubkey-pin-android.zip|Android sample program]], [[Media:pubkey-pin-ios.zip|iOS sample program]], [[Media:pubkey-pin-dotnet.zip|.Net sample program]], and [[Media:pubkey-pin-openssl.zip|OpenSSL sample program]].
+
[[Certificate and Public Key Pinning]] is a technical guide to implementing certificate and public key pinning as discussed at the ''[https://www.owasp.org/index.php/Virginia Virginia chapter's]'' presentation [[Media:Securing-Wireless-Channels-in-the-Mobile-Space.ppt|Securing Wireless Channels in the Mobile Space]]. This guide is focused on providing clear, simple, actionable guidance for securing the channel in a hostile environment where actors could be malicious and the conference of trust a liability.
  
 
A cheat sheet is available at [[Pinning_Cheat_Sheet|Pinning Cheat Sheet]].
 
A cheat sheet is available at [[Pinning_Cheat_Sheet|Pinning Cheat Sheet]].
Line 10: Line 10:
 
The pandemic abuse of trust has resulted in users, developers and applications making security related decisions on untrusted input. The situation is somewhat of a paradox: entities such as DNS and CAs are trusted and supposed to supply trusted input; yet their input cannot be trusted. Relying on untrusted input for security related decisions is not only bad karma, it violates a number of secure coding principals (see, for example, OWASP's [[Injection Theory]] and [[Data Validation]]).
 
The pandemic abuse of trust has resulted in users, developers and applications making security related decisions on untrusted input. The situation is somewhat of a paradox: entities such as DNS and CAs are trusted and supposed to supply trusted input; yet their input cannot be trusted. Relying on untrusted input for security related decisions is not only bad karma, it violates a number of secure coding principals (see, for example, OWASP's [[Injection Theory]] and [[Data Validation]]).
  
Pinning effectively removes the "conference of trust". An application which pins a certificate or public key no longer needs to depend on others - such as DNS or CAs - when making decisions relating to a peer's identity. For those familiar with SSH, you should realize that public key pinning nearly identical to SSH's <tt>StrictHostKeyChecking</tt> option. SSH had it right the entire time, and the rest of the world is beginning to realize the virtues of directly identifying a host or service by its public key.
+
Pinning effectively removes the "conference of trust". An application which pins a certificate or public key no longer needs to depend on others - such as DNS or CAs - when making security decisions relating to a peer's identity. For those familiar with SSH, you should realize that public key pinning is nearly identical to SSH's <tt>StrictHostKeyChecking</tt> option. SSH had it right the entire time, and the rest of the world is beginning to realize the virtues of directly identifying a host or service by its public key.
  
 
Others who actively engage in pinning include Google and its browser Chrome. Chrome was successful in detecting the DigiNotar compromise which uncovered suspected interception by the Iranian government on its citizens. The initial report of the compromise can be found at ''[https://productforums.google.com/d/topic/gmail/3J3r2JqFNTw/discussion Is This MITM Attack to Gmail's SSL?]''; and Google Security's immediate response at ''[https://googleonlinesecurity.blogspot.com/2011/08/update-on-attempted-man-in-middle.html An update on attempted man-in-the-middle attacks]''.
 
Others who actively engage in pinning include Google and its browser Chrome. Chrome was successful in detecting the DigiNotar compromise which uncovered suspected interception by the Iranian government on its citizens. The initial report of the compromise can be found at ''[https://productforums.google.com/d/topic/gmail/3J3r2JqFNTw/discussion Is This MITM Attack to Gmail's SSL?]''; and Google Security's immediate response at ''[https://googleonlinesecurity.blogspot.com/2011/08/update-on-attempted-man-in-middle.html An update on attempted man-in-the-middle attacks]''.
Line 28: Line 28:
 
There are three cures for the key distribution problem. First is to have first hand knowledge of your partner or peer (i.e., a peer, server or service). This could be solved with SneakerNet. Unfortunately, SneakerNet does not scale and cannot be used to solve the key distribution problem.
 
There are three cures for the key distribution problem. First is to have first hand knowledge of your partner or peer (i.e., a peer, server or service). This could be solved with SneakerNet. Unfortunately, SneakerNet does not scale and cannot be used to solve the key distribution problem.
  
The second is to rely on others, and it has two variants: (1) web of trust, and (2) hierarchy of trust. Web of Trust and Hierarchy of Trust solve the key distribution problem in a sterile environment. However, Web of Trust and Hierarchy of Trust each requires us to require us to rely on others - or '''confer trust'''. In practice, trusting others is showing to be problematic.
+
The second is to rely on others, and it has two variants: (1) web of trust, and (2) hierarchy of trust. Web of Trust and Hierarchy of Trust solve the key distribution problem in a sterile environment. However, Web of Trust and Hierarchy of Trust each requires us to rely on others - or '''confer trust'''. In practice, trusting others is showing to be problematic.
  
 
== What Is Pinning? ==
 
== What Is Pinning? ==
Line 34: Line 34:
 
Pinning is the process of associating a host with their ''expected'' X509 certificate or public key. Once a certificate or public key is known or seen for a host, the certificate or public key is associated or 'pinned' to the host. If more than one certificate or public key is acceptable, then the program holds a ''pinset'' (taking from [https://developers.google.com/events/io/sessions/gooio2012/107/ Jon Larimer and Kenny Root Google I/O talk]). In this case, the advertised identity must match one of the elements in the pinset.
 
Pinning is the process of associating a host with their ''expected'' X509 certificate or public key. Once a certificate or public key is known or seen for a host, the certificate or public key is associated or 'pinned' to the host. If more than one certificate or public key is acceptable, then the program holds a ''pinset'' (taking from [https://developers.google.com/events/io/sessions/gooio2012/107/ Jon Larimer and Kenny Root Google I/O talk]). In this case, the advertised identity must match one of the elements in the pinset.
  
A host or service's certificate or public key can be added to an application at development time, or it can be added upon first encountering the certificate or public key. The former - adding at development time - is preferred since ''preloading'' the certificate or public key ''out of band'' usually means the attacker cannot taint the pin.
+
A host or service's certificate or public key can be added to an application at development time, or it can be added upon first encountering the certificate or public key. The former - adding at development time - is preferred since ''preloading'' the certificate or public key ''out of band'' usually means the attacker cannot taint the pin. If the certificate or public key is added upon first encounter, you will be using ''key continuity''. Key continuity can fail if the attacker has a privileged position during the first encounter.
  
Pinning leverages knowledge of the pre-existing relationship between the user and an organization or service to help make better security related decisions. Because you already have information on the server or service, you don't need to rely on generalized mechanisms meant to solve the ''key distribution'' problem. That is, you don't need to turn to DNS for name/address mappings or CAs for bindings and status. Once exception is revocation and it is discussed below in [[#Pinning_Gaps|Pinning Gaps]].
+
Pinning leverages knowledge of the pre-existing relationship between the user and an organization or service to help make better security related decisions. Because you already have information on the server or service, you don't need to rely on generalized mechanisms meant to solve the ''key distribution'' problem. That is, you don't need to turn to DNS for name/address mappings or CAs for bindings and status. One exception is revocation and it is discussed below in [[#Pinning_Gaps|Pinning Gaps]].
  
 
It is also worth mention that Pinning is not Stapling. Stapling sends both the certificate and  OCSP responder information in the same request to avoid the additional fetches the client should perform during path validations.
 
It is also worth mention that Pinning is not Stapling. Stapling sends both the certificate and  OCSP responder information in the same request to avoid the additional fetches the client should perform during path validations.
Line 44: Line 44:
 
You should pin anytime you want to be relatively certain of the remote host's identity or when operating in a hostile environment. Since one or both are almost always true, you should probably pin all the time.
 
You should pin anytime you want to be relatively certain of the remote host's identity or when operating in a hostile environment. Since one or both are almost always true, you should probably pin all the time.
  
A perfect case in point: during the two weeks or so of preparation for the presentation and cheat sheet, we've observed three relevant and related failures. First was [http://gaurangkp.wordpress.com/2013/01/09/nokia-https-mitm/ Nokia/Opera willfully breaking the secure channel]; second was [http://blog.malwarebytes.org/intelligence/2013/02/digital-certificates-and-malware-a-dangerous-mix/ DigiCert issuing a code signing certificate for malware]; and third was [http://krebsonsecurity.com/2013/02/security-firm-bit9-hacked-used-to-spread-malware/ Bit9's loss of its root signing key]. The environment is not only hostile, its toxic.
+
A perfect case in point: during the two weeks or so of preparation for the presentation and cheat sheet, we've observed three relevant and related failures. First was [http://gaurangkp.wordpress.com/2013/01/09/nokia-https-mitm/ Nokia/Opera willfully breaking the secure channel]; second was [http://blog.malwarebytes.org/intelligence/2013/02/digital-certificates-and-malware-a-dangerous-mix/ DigiCert issuing a code signing certificate for malware]; and third was [http://krebsonsecurity.com/2013/02/security-firm-bit9-hacked-used-to-spread-malware/ Bit9's loss of its root signing key]. The environment is not only hostile, it's toxic.
  
 
=== When Do You Whitelist? ===
 
=== When Do You Whitelist? ===
Line 56: Line 56:
 
=== How Do You Pin? ===
 
=== How Do You Pin? ===
  
The idea is to re-use the exiting protocols and infrastructure, but use them in a hardened manner. For re-use, a program would keep doing the things it used to do when establishing a secure connection.
+
The idea is to re-use the existing protocols and infrastructure, but use them in a hardened manner. For re-use, a program would keep doing the things it used to do when establishing a secure connection.
  
To harden the channel, the program would would take advantage of the <tt>OnConnect</tt> callback offered by a library, framework or platform. In the callback, the program would verify the remote host's identity by validating its certificate or public key. While pinning does not have to occur in an <tt>OnConnect</tt> callback, its often most convenient because the underlying connection information is readily available.
+
To harden the channel, the program would take advantage of the <tt>OnConnect</tt> callback offered by a library, framework or platform. In the callback, the program would verify the remote host's identity by validating its certificate or public key. While pinning does not have to occur in an <tt>OnConnect</tt> callback, its often most convenient because the underlying connection information is readily available.
  
 
== What Should Be Pinned? ==
 
== What Should Be Pinned? ==
Line 72: Line 72:
 
A certificate is an object which binds an entity (such as a person or organization) to a public key via a signature. The certificate is DER encoded, and has associated data or attributes such as ''Subject'' (who is identified or bound), ''Issuer'' (who signed it), ''Validity'' (''NotBefore'' and ''NotAfter''), and a ''Public Key''.
 
A certificate is an object which binds an entity (such as a person or organization) to a public key via a signature. The certificate is DER encoded, and has associated data or attributes such as ''Subject'' (who is identified or bound), ''Issuer'' (who signed it), ''Validity'' (''NotBefore'' and ''NotAfter''), and a ''Public Key''.
  
A certificate has a ''subjectPublicKeyInfo''. The subjectPublicKeyInfo is a key with additional information. The ASN.1 type includes an ''Algorithm ID'', a ''Version'', and an extensible format to hold a concrete public key. Figures 1 and 2 below show different views of the same of a RSA key, which is the subjectPublicKeyInfo. The key is for the site [https://www.random.org random.org], and it is used in the sample programs and listings below.
+
A certificate has a ''subjectPublicKeyInfo''. The subjectPublicKeyInfo is a key with additional information. The ASN.1 type includes an ''Algorithm ID'', a ''Version'', and an extensible format to hold a concrete public key. Figures 1 and 2 below show different views of the same RSA key, which is the subjectPublicKeyInfo. The key is for the site [https://www.random.org random.org], and it is used in the sample programs and listings below.
  
 
{| align="center"
 
{| align="center"
Line 107: Line 107:
 
Finally, an organization might want to supply a reserve (or back-up) identity in case the primary identity is compromised. Hashing ensures your adversaries do not see the reserved certificate or public key in advance of its use. In fact, Google's IETF draft ''websec-key-pinning'' uses the technique.
 
Finally, an organization might want to supply a reserve (or back-up) identity in case the primary identity is compromised. Hashing ensures your adversaries do not see the reserved certificate or public key in advance of its use. In fact, Google's IETF draft ''websec-key-pinning'' uses the technique.
  
== What About X509? ==
+
== Examples of Pinning ==
 
 
PKI{X} and the Internet form an intersection. What Internet users expect and what they receive from CAs could vary wildly. For example, an Internet user has security goals, while a CA has revenue goals and legal goals. Many are surprised to learn that the user is often required to perform host identity verification even though the CA issued the certificate (the details are buried in CA warranties on their certificates and their Certification Practice Statement (CPS)).
 
 
 
There are a number of PKI profiles available. For the Internet, "Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL)", also known as [http://tools.ietf.org/rfc/rfc5280.txt RFC 5280], is of interest. Since a certificate is specified in the ITU's X509 standard, there are lots of mandatory and optional fields available for validation from both bodies. Because of the disjoint goals among groups, the next section provides guidance.
 
 
 
=== Mandatory Checks ===
 
 
 
All X509 verifications must include:
 
 
 
* A path validation check. The check verifies all the signatures on certificates in the chain are valid under a given PKI. The check begins at the server or service's certificate (the leaf), and proceeds back to a trusted root certificate (the root).
 
 
 
* A validity check, or the <tt>notBefore</tt> and <tt>notAfter</tt> fields. The <tt>notAfter</tt> field is especially important since a CA will not warrant the certificate after the date, and it does not have to provide CRL/OCSP updates after the date.
 
 
 
* Revocation status. As with <tt>notAfter</tt>, revocation is important because the CA will not warrant a certificate once it is listed as revoked. The IETF approved way of checking a certificate's revocation is OCSP and specified in [http://tools.ietf.org/rfc/rfc2560.txt RFC 2560].
 
 
 
=== Optional Checks ===
 
 
 
<nowiki>[Mulling over what else to present, and the best way to present it. Subject name? DNS lookups? Key Usage? Algorithms? Geolocation based on IP? Check back soon.]</nowiki>
 
 
 
=== Public Key Checks ===
 
 
 
''Quod vide'' (''q.v.''). Verifying the identity of a host with knowledge of its associated/expected public key is pinning.
 
  
== Examples of Pinning ==
+
This section demonstrates certificate and public key pinning in Android Java, iOS, .Net, and OpenSSL.
  
This section demonstrates certificate and public key pinning in Android Java, iOS, .Net, and OpenSSL. All programs attempt to connect to [https://www.random.org random.org] and fetch bytes (Dr. Mads Haahr participates in AOSP's pinning program, so the site should have a static key). The programs enjoy a pre-existing relationship with the site (more correctly, ''a priori'' knowledge), so they include a copy of the site's public key and pin the identity on the key.
+
===HTTP pinning===
 +
[http://www.rfc-editor.org/rfc/rfc7469.txt RFC 7469] introduced a new HTTP header that allows SSL servers to declare hashes of their certificates with time scope in which these certificates should not be changed. For example:
 +
<pre>
 +
Public-Key-Pins: max-age=2592000;
 +
pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=";
 +
pin-sha256="LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ=";
 +
report-uri="http://example.com/pkp-report"
 +
</pre>
  
Parameter validation, return value checking, and error checking have been omitted in the code below, but is present in the sample programs. So the sample code is ready for copy/paste. By far, the most uncomfortable languages are C-based: iOS and OpenSSL.
+
Please note that [http://www.rfc-editor.org/rfc/rfc7469.txt RFC 7469] is controversial since it allows overrides for locally installed authorities. That is, it allows an adversary or other party who successfully phishes the user to override a known good pinset with non-authentic or fraudulent information. Second, the reporting mechanism is suppressed from broken pinsets, so a complying user agent will be complicit in the cover up after the fact. That is, the reporting of the broken pinset is called out as '''MUST NOT''' report [https://en.wikipedia.org/w/index.php?title=HTTP_Public_Key_Pinning [1]].
  
 
=== Android ===
 
=== Android ===
  
Pinning in Android is accomplished through a custom <tt>X509TrustManager</tt>. <tt>X509TrustManager</tt> should perform the customary X509 checks in addition to performing the pin.
+
Since Android N, the preferred way for implementing pinning is by leveraging Android's [https://developer.android.com/training/articles/security-config.html Network Security Configuration] feature, which lets apps customize their network security settings in a safe, declarative configuration file without modifying app code.
 
 
Download: [[Media:pubkey-pin-android.zip|Android sample program]]
 
 
 
<pre>public final class PubKeyManager implements X509TrustManager
 
{
 
  private static String PUB_KEY = "30820122300d06092a864886f70d0101" +
 
    "0105000382010f003082010a0282010100b35ea8adaf4cb6db86068a836f3c85" +
 
    "5a545b1f0cc8afb19e38213bac4d55c3f2f19df6dee82ead67f70a990131b6bc" +
 
    "ac1a9116acc883862f00593199df19ce027c8eaaae8e3121f7f329219464e657" +
 
    "2cbf66e8e229eac2992dd795c4f23df0fe72b6ceef457eba0b9029619e0395b8" +
 
    "609851849dd6214589a2ceba4f7a7dcceb7ab2a6b60c27c69317bd7ab2135f50" +
 
    "c6317e5dbfb9d1e55936e4109b7b911450c746fe0d5d07165b6b23ada7700b00" +
 
    "33238c858ad179a82459c4718019c111b4ef7be53e5972e06ca68a112406da38" +
 
    "cf60d2f4fda4d1cd52f1da9fd6104d91a34455cd7b328b02525320a35253147b" +
 
    "e0b7a5bc860966dc84f10d723ce7eed5430203010001";
 
  
  public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException
+
To enable pinning, [https://developer.android.com/training/articles/security-config.html#CertificatePinning the `<pin-set>` configuration setting] can be used.
  {
 
    if (chain == null) {
 
      throw new IllegalArgumentException("checkServerTrusted: X509Certificate array is null");
 
    }
 
  
    if (!(chain.length > 0)) {
+
If devices running a version of Android that is earlier than N need to be supported, a backport of the Network Security Configuration pinning functionality is available via the TrustKit Android library at https://github.com/datatheorem/TrustKit-Android.
      throw new IllegalArgumentException("checkServerTrusted: X509Certificate is empty");
 
    }
 
  
    if (!(null != authType && authType.equalsIgnoreCase("RSA"))) {
+
Lastly, the Android documentation provides an example of how SSL validation can be customized within the app's code (in order to implement pinning) in the [https://developer.android.com/training/articles/security-ssl.html#UnknownCa Unknown CA implementation document]. However, implementing pinning validation from scratch should be avoided, as implementation mistakes are extremely likely and usually lead to severe vulnerabilities.
      throw new CertificateException("checkServerTrusted: AuthType is not RSA");
 
    }
 
 
 
    // Perform customary SSL/TLS checks
 
    try {
 
      TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
 
      tmf.init((KeyStore) null);
 
     
 
      for (TrustManager trustManager : tmf.getTrustManagers()) {
 
        ((X509TrustManager) trustManager).checkServerTrusted(chain, authType);
 
      }
 
    } catch (Exception e) {
 
      throw new CertificateException(e);
 
    }
 
 
 
    // Hack ahead: BigInteger and toString(). We know a DER encoded Public Key begins
 
    // with 0x30 (ASN.1 SEQUENCE and CONSTRUCTED), so there is no leading 0x00 to drop.
 
    RSAPublicKey pubkey = (RSAPublicKey) chain[0].getPublicKey();
 
    String encoded = new BigInteger(1 /* positive */, pubkey.getEncoded()).toString(16);
 
 
 
    // Pin it!
 
    final boolean expected = PUB_KEY.equalsIgnoreCase(encoded);
 
    if (!expected) {
 
      throw new CertificateException("checkServerTrusted: Expected public key: "
 
                + PUB_KEY + ", got public key:" + encoded);
 
      }
 
    }
 
  }
 
}</pre>
 
 
 
<tt>PubKeyManager</tt> would be used in code similar to below.
 
 
 
<pre>TrustManager tm[] = { new PubKeyManager() };
 
 
 
SSLContext context = SSLContext.getInstance("TLS");
 
context.init(null, tm, null);
 
 
 
URL url = new URL( "https://www.random.org/integers/?" +
 
                  "num=16&min=0&max=255&col=16&base=10&format=plain&rnd=new");
 
 
 
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
 
connection.setSSLSocketFactory(context.getSocketFactory());
 
 
 
InputStreamReader instream = new InputStreamReader(connection.getInputStream());
 
StreamTokenizer tokenizer = new StreamTokenizer(instream);
 
...</pre>
 
  
 
=== iOS ===
 
=== iOS ===
  
iOS pinning is performed through a <tt>NSURLConnectionDelegate</tt>. The delegate must implement <tt>connection:canAuthenticateAgainstProtectionSpace:</tt> and <tt>connection:didReceiveAuthenticationChallenge:</tt>. Within <tt>connection:didReceiveAuthenticationChallenge:</tt>, the delegate must call <tt>SecTrustEvaluate</tt> to perform customary X509 checks.
+
TrustKit, an open-source SSL pinning library for iOS and macOS is available at https://github.com/datatheorem/TrustKit. It provides an easy-to-use API for implementing pinning, and has been deployed in many apps.
 
 
Download: [[Media:pubkey-pin-ios.zip|iOS sample program]].
 
  
<pre>-(IBAction)fetchButtonTapped:(id)sender
+
Otherwise, more details regarding how SSL validation can be customized on iOS (in order to implement pinning) are available in the "HTTPS Server Trust Evaluation" technical note at https://developer.apple.com/library/content/technotes/tn2232/_index.html. However, implementing pinning validation from scratch should be avoided, as implementation mistakes are extremely likely and usually lead to severe vulnerabilities.
{
 
    NSString* requestString = @"https://www.random.org/integers/?
 
        num=16&min=0&max=255&col=16&base=16&format=plain&rnd=new";
 
    NSURL* requestUrl = [NSURL URLWithString:requestString];
 
 
 
    NSURLRequest* request = [NSURLRequest requestWithURL:requestUrl
 
                                            cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
 
                                        timeoutInterval:10.0f];
 
 
 
    NSURLConnection* connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
 
}
 
 
 
-(BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:
 
                  (NSURLProtectionSpace*)space
 
{
 
    return [[space authenticationMethod] isEqualToString: NSURLAuthenticationMethodServerTrust];
 
}
 
 
 
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:
 
                  (NSURLAuthenticationChallenge *)challenge
 
{
 
  if ([[[challenge protectionSpace] authenticationMethod] isEqualToString: NSURLAuthenticationMethodServerTrust])
 
  {
 
    do
 
    {
 
      SecTrustRef serverTrust = [[challenge protectionSpace] serverTrust];
 
      if(nil == serverTrust)
 
        break; /* failed */
 
 
 
      OSStatus status = SecTrustEvaluate(serverTrust, NULL);
 
      if(!(errSecSuccess == status))
 
        break; /* failed */
 
 
 
      SecCertificateRef serverCertificate = SecTrustGetCertificateAtIndex(serverTrust, 0);
 
      if(nil == serverCertificate)
 
        break; /* failed */
 
 
 
      CFDataRef serverCertificateData = SecCertificateCopyData(serverCertificate);
 
      [(id)serverCertificateData autorelease];
 
      if(nil == serverCertificateData)
 
        break; /* failed */
 
 
 
      const UInt8* const data = CFDataGetBytePtr(serverCertificateData);
 
      const CFIndex size = CFDataGetLength(serverCertificateData);
 
      NSData* cert1 = [NSData dataWithBytes:data length:(NSUInteger)size];
 
 
 
      NSString *file = [[NSBundle mainBundle] pathForResource:@"random-org" ofType:@"der"];
 
      NSData* cert2 = [NSData dataWithContentsOfFile:file];
 
 
 
      if(nil == cert1 || nil == cert2)
 
        break; /* failed */
 
 
 
      const BOOL equal = [cert1 isEqualToData:cert2];
 
      if(!equal)
 
        break; /* failed */
 
 
 
      // The only good exit point
 
      return [[challenge sender] useCredential: [NSURLCredential credentialForTrust: serverTrust]
 
                    forAuthenticationChallenge: challenge];
 
    } while(0);
 
 
 
    // Bad dog
 
    return [[challenge sender] cancelAuthenticationChallenge: challenge];
 
}</pre>
 
  
 
=== .Net ===
 
=== .Net ===
Line 449: Line 301:
 
     return result;
 
     return result;
 
}</pre>
 
}</pre>
 
== Pinning Alternatives ==
 
 
Not all applications use split key cryptography. Fortunately, there are protocols which allow you to set up a secure channel based on knowledge of passwords and pre-shared secrets (rather than putting the secret on the wire in a basic authentication scheme). Two are listed below - SRP and PSK. SRP and PSK have [http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-3 88 cipher suites assigned to them by IANA for TLS], so there's no shortage of choices.
 
 
{| align="center"
 
| [[File:pin-iana-assigned.png|thumb|450px|Figure 3: IANA reserved cipher suites for SRP and PSK]]
 
|}
 
 
=== SRP ===
 
 
Secure Remote Password (SRP) is a Password Authenticated Key Exchange (PAKE) by Thomas Wu based upon Diffie-Hellman. The protocol is standardized in [https://tools.ietf.org/rfc/rfc5054.txt RFC 5054] and available in the OpenSSL library (among others). In the SRP scheme, the server uses a verifier which consists of a <tt>{salt, hash(password)}</tt> pair. The user has the password and receives the salt from the server. With lots of hand waiving, both parties select per-instance random values (nonces) and execute the protocol using ''g<sup>{(salt + password)|verifier} + nonces</sup>'' rather than traditional Diffie-Hellman using ''g<sup>ab</sup>''.
 
 
[[File:homer-p-np.jpg|thumb|right|150px|P=NP!!!]]Diffie-Hellman based schemes are part of a family of problems based on Discrete Logs (DL), which are logarithms over a finite field. DL schemes are appealing because they are known to be hard (unless ''P=NP'', which would cause computational number theorists to have a cow).
 
 
 
=== EAP-PSK ===
 
 
EAP-PSK is ''Extensible Authentication Protocol'' using a ''Pre-Shared Key''. EAP-PSK is specified in [https://tools.ietf.org/rfc/rfc4764.txt RFC 4764]. The shared secret is used to key a block cipher, which is in turn used to exchange session keys. EAP-PSK is designed for authentication over insecure networks such as IEEE 802.11.
 
  
 
== Miscellaneous ==
 
== Miscellaneous ==
Line 493: Line 326:
 
Third, help is on its way, and there are a number of futures that will assist with the endeavors:
 
Third, help is on its way, and there are a number of futures that will assist with the endeavors:
  
* Public Key Pinning (http://www.ietf.org/id/draft-ietf-websec-key-pinning-04.txt) – an extension to the HTTP protocol allowing web host operators to instruct user agents (UAs) to remember ("pin") the hosts' cryptographic identities for a given period of time.
+
* Public Key Pinning (http://www.ietf.org/id/draft-ietf-websec-key-pinning-09.txt) – an extension to the HTTP protocol allowing web host operators to instruct user agents (UAs) to remember ("pin") the hosts' cryptographic identities for a given period of time.
 
* DNS-based Authentication of Named Entities (DANE) (https://datatracker.ietf.org/doc/rfc6698/) - uses Secure DNS to associate Certificates with Domain Names For S/MIME, SMTP with TLS, DNSSEC and TLSA records.
 
* DNS-based Authentication of Named Entities (DANE) (https://datatracker.ietf.org/doc/rfc6698/) - uses Secure DNS to associate Certificates with Domain Names For S/MIME, SMTP with TLS, DNSSEC and TLSA records.
 
* Sovereign Keys (http://www.eff.org/sovereign-keys) - operates by providing an optional and secure way of associating domain names with public keys via DNSSEC. PKI (hierarchical) is still used. Semi-centralized with append only logging.
 
* Sovereign Keys (http://www.eff.org/sovereign-keys) - operates by providing an optional and secure way of associating domain names with public keys via DNSSEC. PKI (hierarchical) is still used. Semi-centralized with append only logging.
Line 521: Line 354:
 
* OWASP [[Data_Validation|Data Validation]]
 
* OWASP [[Data_Validation|Data Validation]]
 
* OWASP [[Transport_Layer_Protection_Cheat_Sheet|Transport Layer Protection Cheat Sheet]]
 
* OWASP [[Transport_Layer_Protection_Cheat_Sheet|Transport Layer Protection Cheat Sheet]]
* IETF [http://www.ietf.org/id/draft-ietf-websec-key-pinning-04.txt Public Key Pinning]
+
* IETF [http://www.ietf.org/id/draft-ietf-websec-key-pinning-09.txt Public Key Pinning]
 
* IETF [http://www.ietf.org/rfc/rfc5054.txt RFC 5054 (SRP)]
 
* IETF [http://www.ietf.org/rfc/rfc5054.txt RFC 5054 (SRP)]
 
* IETF [http://www.ietf.org/rfc/rfc4764.txt RFC 4764 (EAP-PSK)]
 
* IETF [http://www.ietf.org/rfc/rfc4764.txt RFC 4764 (EAP-PSK)]
Line 541: Line 374:
 
* Code Project [http://www.codeproject.com/Articles/25487/Cryptographic-Interoperability-Keys Cryptographic Interoperability: Keys]
 
* Code Project [http://www.codeproject.com/Articles/25487/Cryptographic-Interoperability-Keys Cryptographic Interoperability: Keys]
 
* Google I/O [https://developers.google.com/events/io/sessions/gooio2012/107/ Security and Privacy in Android Apps]
 
* Google I/O [https://developers.google.com/events/io/sessions/gooio2012/107/ Security and Privacy in Android Apps]
 +
* Trevor Perrin [https://crypto.stanford.edu/RealWorldCrypto/slides/perrin.pdf Transparency, Trust Agility, Pinning (Recent Developments in Server Authentication)]
 
* Dr. Peter Gutmann's [http://www.cs.auckland.ac.nz/~pgut001/pubs/pkitutorial.pdf PKI is Broken]
 
* Dr. Peter Gutmann's [http://www.cs.auckland.ac.nz/~pgut001/pubs/pkitutorial.pdf PKI is Broken]
 
* Dr. Matthew Green's [http://blog.cryptographyengineering.com/2012/02/how-to-fix-internet.html The Internet is Broken]
 
* Dr. Matthew Green's [http://blog.cryptographyengineering.com/2012/02/how-to-fix-internet.html The Internet is Broken]
 
* Dr. Matthew Green's [http://blog.cryptographyengineering.com/2012/03/how-do-interception-proxies-fail.html How do Interception Proxies fail?]
 
* Dr. Matthew Green's [http://blog.cryptographyengineering.com/2012/03/how-do-interception-proxies-fail.html How do Interception Proxies fail?]
 +
* Presentation: [http://www.slideshare.net/anantshri/ssl-pinning-and-bypasses-android-and-ios SSL Pinning implementation and bypasses for iOS and Android]
  
 
= Authors and Primary Editors  =
 
= Authors and Primary Editors  =
Line 551: Line 386:
 
* Jim Manico - jim, owasp.org
 
* Jim Manico - jim, owasp.org
 
* Kevin Wall - kevin, owasp.org
 
* Kevin Wall - kevin, owasp.org
 +
* Ricardo Iramar - ricardo.iramar, owasp.org
 +
 +
[[Category:Control]]

Latest revision as of 08:06, 22 October 2018

Certificate and Public Key Pinning is a technical guide to implementing certificate and public key pinning as discussed at the Virginia chapter's presentation Securing Wireless Channels in the Mobile Space. This guide is focused on providing clear, simple, actionable guidance for securing the channel in a hostile environment where actors could be malicious and the conference of trust a liability.

A cheat sheet is available at Pinning Cheat Sheet.

Introduction

Secure channels are a cornerstone to users and employees working remotely and on the go. Users and developers expect end-to-end security when sending and receiving data - especially sensitive data on channels protected by VPN, SSL, or TLS. While organizations which control DNS and CA have likely reduced risk to trivial levels under most threat models, users and developers subjugated to other's DNS and a public CA hierarchy are exposed to non-trivial amounts of risk. In fact, history has shown those relying on outside services have suffered chronic breaches in their secure channels.

The pandemic abuse of trust has resulted in users, developers and applications making security related decisions on untrusted input. The situation is somewhat of a paradox: entities such as DNS and CAs are trusted and supposed to supply trusted input; yet their input cannot be trusted. Relying on untrusted input for security related decisions is not only bad karma, it violates a number of secure coding principals (see, for example, OWASP's Injection Theory and Data Validation).

Pinning effectively removes the "conference of trust". An application which pins a certificate or public key no longer needs to depend on others - such as DNS or CAs - when making security decisions relating to a peer's identity. For those familiar with SSH, you should realize that public key pinning is nearly identical to SSH's StrictHostKeyChecking option. SSH had it right the entire time, and the rest of the world is beginning to realize the virtues of directly identifying a host or service by its public key.

Others who actively engage in pinning include Google and its browser Chrome. Chrome was successful in detecting the DigiNotar compromise which uncovered suspected interception by the Iranian government on its citizens. The initial report of the compromise can be found at Is This MITM Attack to Gmail's SSL?; and Google Security's immediate response at An update on attempted man-in-the-middle attacks.

What's the problem?

Users, developers, and applications expect end-to-end security on their secure channels, but some secure channels are not meeting the expectation. Specifically, channels built using well known protocols such as VPN, SSL, and TLS can be vulnerable to a number of attacks.

Examples of past failures are listed on the discussion tab for this article. This cheat sheet does not attempt to catalogue the failures in the industry, investigate the design flaws in the scaffolding, justify the lack of accountability or liability with the providers, explain the race to the bottom in services, or demystify the collusion between, for example, Browsers and CAs. For additional reading, please visit PKI is Broken and The Internet is Broken.

Patient 0

The original problem was the Key Distribution Problem. Insecure communications can be transformed into a secure communication problem with encryption. Encrypted communications can be transformed into an identity problem with signatures. The identity problem terminates at the key distribution problem. They are the same problem.

The Cures

There are three cures for the key distribution problem. First is to have first hand knowledge of your partner or peer (i.e., a peer, server or service). This could be solved with SneakerNet. Unfortunately, SneakerNet does not scale and cannot be used to solve the key distribution problem.

The second is to rely on others, and it has two variants: (1) web of trust, and (2) hierarchy of trust. Web of Trust and Hierarchy of Trust solve the key distribution problem in a sterile environment. However, Web of Trust and Hierarchy of Trust each requires us to rely on others - or confer trust. In practice, trusting others is showing to be problematic.

What Is Pinning?

Pinning is the process of associating a host with their expected X509 certificate or public key. Once a certificate or public key is known or seen for a host, the certificate or public key is associated or 'pinned' to the host. If more than one certificate or public key is acceptable, then the program holds a pinset (taking from Jon Larimer and Kenny Root Google I/O talk). In this case, the advertised identity must match one of the elements in the pinset.

A host or service's certificate or public key can be added to an application at development time, or it can be added upon first encountering the certificate or public key. The former - adding at development time - is preferred since preloading the certificate or public key out of band usually means the attacker cannot taint the pin. If the certificate or public key is added upon first encounter, you will be using key continuity. Key continuity can fail if the attacker has a privileged position during the first encounter.

Pinning leverages knowledge of the pre-existing relationship between the user and an organization or service to help make better security related decisions. Because you already have information on the server or service, you don't need to rely on generalized mechanisms meant to solve the key distribution problem. That is, you don't need to turn to DNS for name/address mappings or CAs for bindings and status. One exception is revocation and it is discussed below in Pinning Gaps.

It is also worth mention that Pinning is not Stapling. Stapling sends both the certificate and OCSP responder information in the same request to avoid the additional fetches the client should perform during path validations.

When Do You Pin?

You should pin anytime you want to be relatively certain of the remote host's identity or when operating in a hostile environment. Since one or both are almost always true, you should probably pin all the time.

A perfect case in point: during the two weeks or so of preparation for the presentation and cheat sheet, we've observed three relevant and related failures. First was Nokia/Opera willfully breaking the secure channel; second was DigiCert issuing a code signing certificate for malware; and third was Bit9's loss of its root signing key. The environment is not only hostile, it's toxic.

When Do You Whitelist?

If you are working for an organization which practices "egress filtering" as part of a Data Loss Prevention (DLP) strategy, you will likely encounter Interception Proxies. I like to refer to these things as "good" bad guys (as opposed to "bad" bad guys) since both break end-to-end security and we can't tell them apart. In this case, do not offer to whitelist the interception proxy since it defeats your security goals. Add the interception proxy's public key to your pinset after being instructed to do so by the folks in Risk Acceptance.

Note: if you whitelist a certificate or public key for a different host (for example, to accommodate an interception proxy), you are no longer pinning the expected certificates and keys for the host. Security and integrity on the channel could suffer, and it surely breaks end-to-end security expectations of users and organizations.

For more reading on interception proxies, the additional risk they bestow, and how they fail, see Dr. Matthew Green's How do Interception Proxies fail? and Jeff Jarmoc's BlackHat talk SSL/TLS Interception Proxies and Transitive Trust.

How Do You Pin?

The idea is to re-use the existing protocols and infrastructure, but use them in a hardened manner. For re-use, a program would keep doing the things it used to do when establishing a secure connection.

To harden the channel, the program would take advantage of the OnConnect callback offered by a library, framework or platform. In the callback, the program would verify the remote host's identity by validating its certificate or public key. While pinning does not have to occur in an OnConnect callback, its often most convenient because the underlying connection information is readily available.

What Should Be Pinned?

The first thing to decide is what should be pinned. For this choice, you have two options: you can (1) pin the certificate; or (2) pin the public key. If you choose public keys, you have two additional choices: (a) pin the subjectPublicKeyInfo; or (b) pin one of the concrete types such as RSAPublicKey or DSAPublicKey.

The three choices are explained below in more detail. I would encourage you to pin the subjectPublicKeyInfo because it has the public parameters (such as {e,n} for an RSA public key) and contextual information such as an algorithm and OID. The context will help you keep your bearings at times, and Figure 1 below shows the additional information available.

Encodings/Formats

For the purposes of this article, the objects are in X509-compatible presentation format (PKCS#1 defers to X509, both of which use ASN.1). If you have a PEM encoded object (for example, -----BEGIN CERTIFICATE-----, -----END CERTIFICATE-----), then convert the object to DER encoding. Conversion using OpenSSL is offered below in Format Conversions.

A certificate is an object which binds an entity (such as a person or organization) to a public key via a signature. The certificate is DER encoded, and has associated data or attributes such as Subject (who is identified or bound), Issuer (who signed it), Validity (NotBefore and NotAfter), and a Public Key.

A certificate has a subjectPublicKeyInfo. The subjectPublicKeyInfo is a key with additional information. The ASN.1 type includes an Algorithm ID, a Version, and an extensible format to hold a concrete public key. Figures 1 and 2 below show different views of the same RSA key, which is the subjectPublicKeyInfo. The key is for the site random.org, and it is used in the sample programs and listings below.

Figure 1: subjectPublicKeyInfo dumped with dumpans1
Figure 2: subjectPublicKeyInfo under a hex editor

The concrete public key is an encoded public key. The key format will usually be specified elsewhere - for example, PKCS#1 in the case of RSA Public Keys. In the case of an RSA public key, the type is RSAPublicKey and the parameters {e,n} will be ASN.1 encoded. Figures 1 and 2 above clearly show the modulus (n at line 28) and exponent (e at line 289). For DSA, the concrete type is DSAPublicKey and the ASN.1 encoded parameters would be {p,q,g,y}.

Final takeaways: (1) a certificate binds an entity to a public key; (2) a certificate has a subjectPublicKeyInfo; and (3) a subjectPublicKeyInfo has an concrete public key. For those who want to learn more, a more in-depth discussion from a programmer's perspective can be found at the Code Project's article Cryptographic Interoperability: Keys.

Certificate

Certificate
The certificate is easiest to pin. You can fetch the certificate out of band for the website, have the IT folks email your company certificate to you, use openssl s_client to retrieve the certificate etc. When the certificate expires, you would update your application. Assuming your application has no bugs or security defects, the application would be updated every year or two.

At runtime, you retrieve the website or server's certificate in the callback. Within the callback, you compare the retrieved certificate with the certificate embedded within the program. If the comparison fails, then fail the method or function.

There is a downside to pinning a certificate. If the site rotates its certificate on a regular basis, then your application would need to be updated regularly. For example, Google rotates its certificates, so you will need to update your application about once a month (if it depended on Google services). Even though Google rotates its certificates, the underlying public keys (within the certificate) remain static.

Public Key

Public Key
Public key pinning is more flexible but a little trickier due to the extra steps necessary to extract the public key from a certificate. As with a certificate, the program checks the extracted public key with its embedded copy of the public key.

There are two downsides two public key pinning. First, its harder to work with keys (versus certificates) since you usually must extract the key from the certificate. Extraction is a minor inconvenience in Java and .Net, buts its uncomfortable in Cocoa/CocoaTouch and OpenSSL. Second, the key is static and may violate key rotation policies.

Hashing

While the three choices above used DER encoding, its also acceptable to use a hash of the information (or other transforms). In fact, the original sample programs were written using digested certificates and public keys. The samples were changed to allow a programmer to inspect the objects with tools like dumpasn1 and other ASN.1 decoders.

Hashing also provides three additional benefits. First, hashing allows you to anonymize a certificate or public key. This might be important if you application is concerned about leaking information during decompilation and re-engineering.

Second, a digested certificate fingerprint is often available as a native API for many libraries, so its convenient to use.

Finally, an organization might want to supply a reserve (or back-up) identity in case the primary identity is compromised. Hashing ensures your adversaries do not see the reserved certificate or public key in advance of its use. In fact, Google's IETF draft websec-key-pinning uses the technique.

Examples of Pinning

This section demonstrates certificate and public key pinning in Android Java, iOS, .Net, and OpenSSL.

HTTP pinning

RFC 7469 introduced a new HTTP header that allows SSL servers to declare hashes of their certificates with time scope in which these certificates should not be changed. For example:

Public-Key-Pins: max-age=2592000;
pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=";
pin-sha256="LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ=";
report-uri="http://example.com/pkp-report"

Please note that RFC 7469 is controversial since it allows overrides for locally installed authorities. That is, it allows an adversary or other party who successfully phishes the user to override a known good pinset with non-authentic or fraudulent information. Second, the reporting mechanism is suppressed from broken pinsets, so a complying user agent will be complicit in the cover up after the fact. That is, the reporting of the broken pinset is called out as MUST NOT report [1].

Android

Since Android N, the preferred way for implementing pinning is by leveraging Android's Network Security Configuration feature, which lets apps customize their network security settings in a safe, declarative configuration file without modifying app code.

To enable pinning, the `<pin-set>` configuration setting can be used.

If devices running a version of Android that is earlier than N need to be supported, a backport of the Network Security Configuration pinning functionality is available via the TrustKit Android library at https://github.com/datatheorem/TrustKit-Android.

Lastly, the Android documentation provides an example of how SSL validation can be customized within the app's code (in order to implement pinning) in the Unknown CA implementation document. However, implementing pinning validation from scratch should be avoided, as implementation mistakes are extremely likely and usually lead to severe vulnerabilities.

iOS

TrustKit, an open-source SSL pinning library for iOS and macOS is available at https://github.com/datatheorem/TrustKit. It provides an easy-to-use API for implementing pinning, and has been deployed in many apps.

Otherwise, more details regarding how SSL validation can be customized on iOS (in order to implement pinning) are available in the "HTTPS Server Trust Evaluation" technical note at https://developer.apple.com/library/content/technotes/tn2232/_index.html. However, implementing pinning validation from scratch should be avoided, as implementation mistakes are extremely likely and usually lead to severe vulnerabilities.

.Net

.Net pinning can be achieved by using ServicePointManager as shown below.

Download: .Net sample program.

// Encoded RSAPublicKey
private static String PUB_KEY = "30818902818100C4A06B7B52F8D17DC1CCB47362" +
    "C64AB799AAE19E245A7559E9CEEC7D8AA4DF07CB0B21FDFD763C63A313A668FE9D764E" +
    "D913C51A676788DB62AF624F422C2F112C1316922AA5D37823CD9F43D1FC54513D14B2" +
    "9E36991F08A042C42EAAEEE5FE8E2CB10167174A359CEBF6FACC2C9CA933AD403137EE" +
    "2C3F4CBED9460129C72B0203010001";

public static void Main(string[] args)
{
  ServicePointManager.ServerCertificateValidationCallback = PinPublicKey;
  WebRequest wr = WebRequest.Create("https://encrypted.google.com/");
  wr.GetResponse();
}

public static bool PinPublicKey(object sender, X509Certificate certificate, X509Chain chain,
                                SslPolicyErrors sslPolicyErrors)
{
  if (null == certificate)
    return false;

  String pk = certificate.GetPublicKeyString();
  if (pk.Equals(PUB_KEY))
    return true;

  // Bad dog
  return false;
}

OpenSSL

Pinning can occur at one of two places with OpenSSL. First is the user supplied verify_callback. Second is after the connection is established via SSL_get_peer_certificate. Either method will allow you to access the peer's certificate.

Though OpenSSL performs the X509 checks, you must fail the connection and tear down the socket on error. By design, a server that does not supply a certificate will result in X509_V_OK with a NULL certificate. To check the result of the customary verification: (1) you must call SSL_get_verify_result and verify the return code is X509_V_OK; and (2) you must call SSL_get_peer_certificate and verify the certificate is non-NULL.

Download: OpenSSL sample program.

int pkp_pin_peer_pubkey(SSL* ssl)
{
    if(NULL == ssl) return FALSE;
    
    X509* cert = NULL;
    FILE* fp = NULL;
    
    /* Scratch */
    int len1 = 0, len2 = 0;
    unsigned char *buff1 = NULL, *buff2 = NULL;
    
    /* Result is returned to caller */
    int ret = 0, result = FALSE;
    
    do
    {
        /* http://www.openssl.org/docs/ssl/SSL_get_peer_certificate.html */
        cert = SSL_get_peer_certificate(ssl);
        if(!(cert != NULL))
            break; /* failed */
        
        /* Begin Gyrations to get the subjectPublicKeyInfo       */
        /* Thanks to Viktor Dukhovni on the OpenSSL mailing list */
        
        /* http://groups.google.com/group/mailing.openssl.users/browse_thread/thread/d61858dae102c6c7 */
        len1 = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), NULL);
        if(!(len1 > 0))
            break; /* failed */
        
        /* scratch */
        unsigned char* temp = NULL;
        
        /* http://www.openssl.org/docs/crypto/buffer.html */
        buff1 = temp = OPENSSL_malloc(len1);
        if(!(buff1 != NULL))
            break; /* failed */
        
        /* http://www.openssl.org/docs/crypto/d2i_X509.html */
        len2 = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), &temp);

        /* These checks are verifying we got back the same values as when we sized the buffer.      */
        /* Its pretty weak since they should always be the same. But it gives us something to test. */
        if(!((len1 == len2) && (temp != NULL) && ((temp - buff1) == len1)))
            break; /* failed */
        
        /* End Gyrations */
        
        /* See the warning above!!!                                            */
        /* http://pubs.opengroup.org/onlinepubs/009696699/functions/fopen.html */
        fp = fopen("random-org.der", "rx");
        if(NULL ==fp) {
            fp = fopen("random-org.der", "r");
        
        if(!(NULL != fp))
            break; /* failed */
        
        /* Seek to eof to determine the file's size                            */
        /* http://pubs.opengroup.org/onlinepubs/009696699/functions/fseek.html */
        ret = fseek(fp, 0, SEEK_END);
        if(!(0 == ret))
            break; /* failed */
        
        /* Fetch the file's size                                               */
        /* http://pubs.opengroup.org/onlinepubs/009696699/functions/ftell.html */
        long size = ftell(fp);

        /* Arbitrary size, but should be relatively small (less than 1K or 2K) */
        if(!(size != -1 && size > 0 && size < 2048))
            break; /* failed */
        
        /* Rewind to beginning to perform the read                             */
        /* http://pubs.opengroup.org/onlinepubs/009696699/functions/fseek.html */
        ret = fseek(fp, 0, SEEK_SET);
        if(!(0 == ret))
            break; /* failed */
        
        /* Re-use buff2 and len2 */
        buff2 = NULL; len2 = (int)size;
        
        /* http://www.openssl.org/docs/crypto/buffer.html */
        buff2 = OPENSSL_malloc(len2);
        if(!(buff2 != NULL))
            break; /* failed */
        
        /* http://pubs.opengroup.org/onlinepubs/009696699/functions/fread.html */
        /* Returns number of elements read, which should be 1 */
        ret = (int)fread(buff2, (size_t)len2, 1, fp);
        if(!(ret == 1))
            break; /* failed */
        
        /* Re-use size. MIN and MAX macro below... */
        size = len1 < len2 ? len1 : len2;
        
        /*************************/
        /*****    PAYDIRT    *****/
        /*************************/
        if(len1 != (int)size || len2 != (int)size || 0 != memcmp(buff1, buff2, (size_t)size))
            break; /* failed */
        
        /* The one good exit point */
        result = TRUE;
        
    } while(0);
    
    if(fp != NULL)
        fclose(fp);
    
    /* http://www.openssl.org/docs/crypto/buffer.html */
    if(NULL != buff2)
        OPENSSL_free(buff2);
    
    /* http://www.openssl.org/docs/crypto/buffer.html */
    if(NULL != buff1)
        OPENSSL_free(buff1);
    
    /* http://www.openssl.org/docs/crypto/X509_new.html */
    if(NULL != cert)
        X509_free(cert);
    
    return result;
}

Miscellaneous

This sections covers administrivia and miscellaneous items related to pinning.

Ephemeral Keys

Ephemeral keys are temporary keys used for one instance of a protocol execution and then thrown away. An ephemeral key has the benefit of providing forward secrecy, meaning a compromise of the site or service's long term (static) signing key does not facilitate decrypting past messages because the key was temporary and discarded (once the session terminated).

Ephemeral keys do not affect pinning because the Ephemeral key is delivered in a separate ServerKeyExchange message. In addition, the ephemeral key is a key and not a certificate, so it does not change the construction of the certificate chain. That is, the certificate of interest will still be located at certificates[0].

Pinning Gaps

There are two gaps when pinning due to reuse of the existing infrastructure and protocols. First, an explicit challenge is not sent by the program to the peer server based on the server's public information. So the program never knows if the peer can actually decrypt messages. However, the shortcoming is usually academic in practice since an adversary will receive messages it can't decrypt.

Second is revocation. Clients don't usually engage in revocation checking, so it could be possible to use a known bad certificate or key in a pinset. Even if revocation is active, Certificate Revocation Lists (CRLs) and Online Certificate Status Protocol (OCSP) can be defeated in a hostile environment. An application can take steps to remediate, with the primary means being freshness. That is, an application should be updated and distributed immediately when a critical security parameter changes.

No Relationship ^@$!

If you don't have a pre-existing relationship, all is not lost. First, you can pin a host or server's certificate or public key the first time you encounter it. If the bad guy was not active when you encountered the certificate or public key, he or she will not be successful with future funny business.

Second, bad certificates are being spotted quicker in the field due to projects like Chromium and Certificate Patrol, and initiatives like the EFF's SSL Observatory.

Third, help is on its way, and there are a number of futures that will assist with the endeavors:

  • Public Key Pinning (http://www.ietf.org/id/draft-ietf-websec-key-pinning-09.txt) – an extension to the HTTP protocol allowing web host operators to instruct user agents (UAs) to remember ("pin") the hosts' cryptographic identities for a given period of time.
  • DNS-based Authentication of Named Entities (DANE) (https://datatracker.ietf.org/doc/rfc6698/) - uses Secure DNS to associate Certificates with Domain Names For S/MIME, SMTP with TLS, DNSSEC and TLSA records.
  • Sovereign Keys (http://www.eff.org/sovereign-keys) - operates by providing an optional and secure way of associating domain names with public keys via DNSSEC. PKI (hierarchical) is still used. Semi-centralized with append only logging.
  • Convergence (http://convergence.io) – different [geographical] views of a site and its associated data (certificates and public keys). Web of Trust is used. Semi-centralized.

While Sovereign Keys and Convergence still require us to confer trust to outside parties, the parties involved do not serve share holders or covet revenue streams. Their interests are industry transparency and user security.

More Information?

Pinning is an old new thing that has been shaken, stirred, and repackaged. While "pinning" and "pinsets" are relatively new terms for old things, Jon Larimer and Kenny Root spent time on the subject at Google I/O 2012 with their talk Security and Privacy in Android Apps.

Format Conversions

As a convenience to readers, the following with convert between PEM and DER format using OpenSSL.

# Public key, X509
$ openssl genrsa -out rsa-openssl.pem 3072
$ openssl rsa -in rsa-openssl.pem -pubout -outform DER -out rsa-openssl.der
# Private key, PKCS#8
$ openssl genrsa -out rsa-openssl.pem 3072
$ openssl pkcs8 -nocrypt -in rsa-openssl.pem -inform PEM -topk8 -outform DER -out rsa-openssl.der

References

Authors and Primary Editors

  • Jeffrey Walton - jeffrey, owasp.org
  • JohnSteven - john, owasp.org
  • Jim Manico - jim, owasp.org
  • Kevin Wall - kevin, owasp.org
  • Ricardo Iramar - ricardo.iramar, owasp.org