On Thursday, 30 July 2015 01:35:52 UTC+2, David Keeler  wrote:
> [cc'd to dev-security for visibility. This discussion is intended to
> happen on dev-platform; please reply to that list.]
> 
> Ryan Sleevi recently announced the pre-intention to deprecate and
> eventually remove support for the <keygen> element and special-case
> handling of the application/x-x509-*-cert MIME types from the blink
> platform (i.e. Chrome).
> 
> Rather than reiterate his detailed analysis, I'll refer to the post here:
> 
> https://groups.google.com/a/chromium.org/d/msg/blink-dev/pX5NbX0Xack/kmHsyMGJZAMJ
> 

One of the elements of his detailed analysis is under fire, namely that the 
reliance of keygen on PEM is a key security hole. I made this case in more 
detail here:
https://github.com/whatwg/html/issues/102

But to avoid your needing to click on the link here it is in full:

<keygen> has been deprecated a few days ago, and the issue has been taken up by 
@timbl on the Technical Architecture Group as it removes a useful tool in the 
asymmetric public key cryptography available in browsers.

One reason given for deprecating that recurs often is that keygen uses MD5 
which opens an attack vector presented in a very good paper "MD5 considered 
harmful today" at the Chaos Communication Congress in Berlin in 2008 by a 
number of researchers of which Jacob Appelbaum ( aka. @ioerror ) . ( That was 
the time when Julian Assange was working freely on Wikileaks, so you can even 
hear him ask a question at the end )

The slides are here:
https://www.trailofbits.com/resources/creating_a_rogue_ca_cert_slides.pdf
The video is here:
http://chaosradio.ccc.de/25c3_m4v_3023.html

In short they were able to create a fake Certificate Authority (CA) because the 
CA signed its certificates with MD5 and they were able to create hash 
collisions, to use the certificate signed by the CA
and change some information in it to produce their own top level certificate, 
with which
they could create a certificate for any site they wished to! ( Pretty awesomely 
bad - though they did this carefully to avoid misuse ). This is why projects 
such as IETFs DANE, DNSSEC, and many other improvements to the internet 
infrastructure are vital.

This was 7 years ago, so all of this should be fixed by now. There should be no 
CA signing 
Server Certificates with MD5 anymore.

Great. But that has nothing to do with what is going on with <keygen>. The 
problem
may well be that the documentation of <keygen> is misleading here. The WHATWG 
documentation on keygen currently states:

If the keytype attribute is in the RSA state: Generate an RSA key pair using 
the settings given by the user, if appropriate, using the md5WithRSAEncryption 
RSA signature algorithm (the signature algorithm with MD5 and the RSA 
encryption algorithm) referenced in section 2.2.1 ("RSA Signature Algorithm") 
of RFC 3279, and defined in RFC 3447. [RFC3279] [RFC3447]
By whether or not keygen wraps the key and signs it with MD5 is of not much 
importance, since this is the keyrequest we are speaking of here, not the 
generated certificate!

To summarise how the keygen is actually used: 
1. The browser creates a public/private key, saves the private key in the 
secure keychain 
2. and sends the public key in an spkac request to the server which 
3. which on receipt of the certificate request and verification of the data, 
uses that to create a Client Certificate using any signature algorithm it wants 
for the creation of the certificate ( And so it SHOULD NOT USE MD5: see CCC 
talk above )
4. which it returns using one of the x509 mime types available to it,

Here is an illustration of the flow that we use in the WebID-TLS spec to 
illustrate this:
Certificate Creation Flow

http://www.w3.org/2005/Incubator/webid/spec/tls/#certificate-creation

To see some real code implementing this I point you to my 
ClientCertificateApp.scala code that receives a certificate Request, and either 
returns an error or a certificate.
The key parts of the code are extracted below
https://github.com/read-write-web/rww-play/blob/f587382935c85e9f8916d5065434f7525c328ab9/app/controllers/ClientCertificateApp.scala

def generate = Action { implicit request =>
    certForm.bindFromRequest.fold(
      errors => BadRequest(html.webid.cert.genericCertCreator(errors)),
      certreq => {
        Result(
          
//https://developer.mozilla.org/en-US/docs/NSS_Certificate_Download_Specification
          header = ResponseHeader(200, Map("Content-Type" -> 
"application/x-x509-user-cert")),
          body   = Enumerator(certreq.certificate.getEncoded)
        )
      }
    )
}

CertForm just takes the data from the html form (verifies all fields are ok) 
and generates a CertReq object. ( or it can also take a CertReq object and 
generate a form, so that errors can be shown to the user )

val certForm = Form(
  mapping(
    "CN" -> email,
    "webids" -> list(of[Option[URI]]).
      transform[List[URI]](_.flatten,_.map(e=>Some(e))).
      verifying("require at least one WebID", _.size > 0),
    "spkac" -> of(spkacFormatter),
    "years" -> number(min=1,max=20)
  )((CN, webids, pubkey,years) => 
CertReq(CN,webids,pubkey,tenMinutesAgo,yearsFromNow(years)))
    ((req: CertReq) => Some(req.cn,req.webids,null,2))
)

The spkacFormatter just returns a public key. ( It plays around with testing 
the challenge, but I am not sure what that is for - would like to know ).

Anyway as I wrote above: if successful the generate method returns an encoded 
certificate with the right mime type. And as you can see we create a 
certificate with SHA1withRSA

val sigAlgId = new 
DefaultSignatureAlgorithmIdentifierFinder().find("SHA1withRSA")
val digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId)
val rsaParams = CertReq.issuerKey.getPrivate match {
  case k: RSAPrivateCrtKey =>
    new RSAPrivateCrtKeyParameters(
      k.getModulus(), k.getPublicExponent(), k.getPrivateExponent(),
      k.getPrimeP(), k.getPrimeQ(), k.getPrimeExponentP(), 
k.getPrimeExponentQ(),
      k.getCrtCoefficient());
  case k: RSAPrivateKey =>
    new RSAKeyParameters(true, k.getModulus(), k.getPrivateExponent());
}


val sigGen = new BcRSAContentSignerBuilder(sigAlgId, digAlgId).build(rsaParams);
x509Builder.build(sigGen)
So the MD5 plays no serious role in all this.

This should not be a big surprise. The only thing of value sent to the server 
is the public key. It sends back a certificate based on that public key ( and 
other information it may have on the user ). But the only one to be able to use 
that certificate is the person owning the private key.

Now my code could presumably be improved in many places I doubt not. But this 
should show how
<keygen> is actually used. After all remember that <keygen> was added 10 years 
after it appeared in browsers, and that there was not that much discussion 
about the documentation when it was added.

I then posted a certificate I created using keygen and the server code 
described above. As you can see from the openssl command there is no MD5 in the 
resulting certificate.

$ openssl pkcs12 -clcerts -nokeys -in ~/Certificates.p12  | openssl x509 -noout 
-text
Enter Import Password:
MAC verified OK
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            01:4c:19:67:ea:05
        Signature Algorithm: sha1WithRSAEncryption
        Issuer: CN=WebID, O={}
        Validity
            Not Before: Mar 14 17:39:42 2015 GMT
            Not After : Mar 13 17:49:42 2019 GMT
        Subject: dnQualifier=he...@bblfish.net
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
            RSA Public Key: (2048 bit)
                Modulus (2048 bit):
                    00:da:b9:d1:e9:41:f6:f8:5a:08:63:16:9d:0d:b6:
                    32:8d:1d:4a:15:a7:1d:ff:e3:d4:f4:d0:87:52:a5:
                    2f:b1:45:4d:73:58:e4:a5:ec:f3:50:1e:39:24:bc:
                    02:52:f3:00:4b:0b:b2:1a:0d:6b:64:ca:05:3f:0f:
                    bc:b5:a5:4e:c9:3e:be:2d:c9:b9:1e:4c:43:2b:82:
                    78:84:c4:cc:2a:d8:a1:02:b4:6d:2a:20:17:bf:45:
                    d9:d4:c8:8a:56:4d:42:02:34:48:4a:1b:2e:44:6d:
                    bb:4c:d4:38:e7:9c:24:66:ce:31:0f:32:77:73:a7:
                    79:d2:4e:d7:b6:0a:05:a6:18:b9:84:75:7b:94:6d:
                    67:ba:79:f2:e0:64:e6:ae:d3:8b:d6:55:9c:e7:fc:
                    95:02:72:08:23:d5:6d:b1:c0:34:09:93:67:d7:db:
                    27:b6:bd:af:da:8c:c4:83:47:13:3f:4a:14:67:5f:
                    67:5f:b4:84:ce:32:df:66:c1:1a:36:38:fa:84:d5:
                    be:69:b1:a6:f2:38:11:5d:ef:9b:0f:79:bb:25:c0:
                    cb:7e:4a:39:45:9a:08:29:b1:fd:35:c0:d1:db:dd:
                    60:f9:c6:79:d8:94:15:ed:7e:a4:1e:b0:2f:bc:01:
                    6f:c0:e7:92:cb:96:98:c9:f4:db:84:2c:da:d5:b5:
                    f5:c9
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Alternative Name: critical
                URI:http://bblfish.net/people/henry/card#me
            X509v3 Key Usage: critical
                Digital Signature, Non Repudiation, Key Encipherment, Key 
Agreement, Certificate Sign
            X509v3 Basic Constraints: critical
                CA:FALSE
            Netscape Cert Type: 
                SSL Client, S/MIME
    Signature Algorithm: sha1WithRSAEncryption
        03:25:38:47:76:34:ba:da:0b:40:ea:75:63:98:6b:b0:0b:b6:
        11:85:c7:b1:c4:91:cc:5c:99:a5:b5:01:24:6f:1f:8c:03:39:
        80:03:e7:50:59:9f:b0:48:6e:e7:16:b8:b7:92:6f:31:cd:cc:
        ba:60:40:08:9e:3c:38:5d:19:94:fd:2c:be:6d:84:57:d4:ea:
        7f:54:a7:69:73:aa:37:a4:b8:81:21:0c:65:dc:f1:f6:a3:40:
        d1:18:cf:04:a4:d6:8b:9a:1f:43:c2:67:4a:0e:8d:00:b7:e8:
        49:e3:b7:d5:f9:00:0f:98:32:b2:09:5e:ca:c0:44:37:dc:df:
        3b:57:e0:c2:5a:8a:79:0d:55:7a:4a:73:4a:24:64:27:e5:16:
        78:d4:c9:35:5e:f8:67:9c:e9:41:bd:c6:25:6b:1b:d7:03:c1:
        af:64:d0:e3:0a:ea:58:a4:bc:3a:a4:8f:51:8d:33:58:ed:ba:
        af:3d:b7:75:28:32:33:76:65:80:56:ae:ec:43:db:9e:7e:4b:
        74:f5:88:07:9f:2d:e8:74:f1:89:d1:af:52:34:07:52:f3:54:
        2f:60:fd:de:96:f6:00:67:2e:8f:10:23:e6:af:95:bf:a6:3c:
        61:0d:8c:24:47:cf:52:45:0f:96:ee:ca:3a:69:82:69:3b:20:
        87:06:5c:58

Watch out that if you look at this certificate with viewers such as OSX 
keychain they will nevertheless show an MD5 signature - but that is not in the 
certificate itself. I checked with the openssl folks.

_______________________________________________
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform

Reply via email to