GithubHelp home page GithubHelp logo

briansmith / webpki Goto Github PK

View Code? Open in Web Editor NEW
456.0 21.0 165.0 681 KB

WebPKI X.509 Certificate Validation in Rust

Home Page: https://briansmith.org/rustdoc/webpki/

License: Other

Shell 10.35% Rust 89.53% PowerShell 0.11%
webpki rust pkix certificate x509

webpki's Introduction

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

What is webpki?

webpki is a library that validates Web PKI (TLS/SSL) certificates. webpki is designed to provide a full implementation of the client side of the Web PKI to a diverse range of applications and devices, including embedded (IoT) applications, mobile apps, desktop applications, and server infrastructure. webpki is intended to not only be the best implementation of the Web PKI, but to also precisely define what the Web PKI is.

webpki is written in Rust and uses ring for signature verification.

webpki is strongly influenced by mozilla::pkix. You can read a little about the ideas underlying both mozilla::pkix and webpki in insanity::pkix: A New Certificate Path Building & Validation Library.

The Rust compiler statically guarantees there are no buffer overflows, uses-after-free, double-frees, data races, etc. in webpki. webpki takes advantage of Rust's borrow checker to ensure that its zero-copy parsing strategy is safe and efficient. webpki never allocates memory on the heap, and it maintains a tight bound on the amount of stack memory it uses. webpki avoids all superfluous PKIX features in order to keep its object code size small. Further reducing the code size of webpki is an important goal.

This release is the very first prototype. Lots of improvements are planned, including:

  • An extensive automated test suite.
  • Key pinning.
  • Certificate Transparency support.
  • Short-lived certificate, OCSP stapling, and CRLSet support.
  • Customization of the supported algorithms, key sizes, and elliptic curves allowed during a validation.
  • A C language wrapper interface to allow using webpki in non-Rust applications.
  • A specification of precisely what the Web PKI is.

Demo

See https://github.com/ctz/rustls#example-code for an example of using webpki.

License

See LICENSE. This project happily accepts pull requests without any formal copyright/contributor license agreement. Pull requests must explicitly indicate who owns the copyright to the code being contributed and that the code is being licensed under the same terms as the existing webpki code.

Bug Reporting

Please report bugs either as pull requests or as issues in the issue tracker. webpki has a full disclosure vulnerability policy. Please do NOT attempt to report any security vulnerability in this code privately to anybody.

webpki's People

Contributors

alex avatar briansmith avatar cpu avatar ctz avatar decathorpe avatar euclio avatar fralalonde avatar frewsxcv avatar geogriff-signal avatar jonas-schievink avatar king6cong avatar lalitmaganti avatar mattmahn avatar njsmith avatar satlank avatar shahn avatar stepancheg avatar timwolla avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

webpki's Issues

Add Must-Staple support.

Add support for the Must-Staple part of the X.509 Feature Extension (RFC 7633) to the validator, such that a certificate will fail validation if a valid OCSP response isn't provided in the call.

Add RSA-PSS support

Depends on, at least, briansmith/ring#262.

The RSA-PSS tests imported from Chromium will need to be modified from expect-failure to expect-success.

One open question is whether to support SHA-1 as the MGF digest and/or whether to require the MGF digest algorithm to match the signature digest algorithm and/or whether to require the salt to be the length of the digest output. Certificates generated using Microsoft's tools only use SHA-1 with 20-byte salts.

Create a `PresentedDNSID` type to represented DNS IDs in certificates

When investigating an issue mentioned in #65 I thought "Why not change GeneralName::DNSName(untrusted::Input<'a>) to GeneralName::DNSName(DNSNameRef<'a>)?". I started down that path. However, I then was reminded by the code that GeneralName::DNSName is not a DNS name, but a "presented DNS ID." A presented DNS ID can either be a DNS name (DNSNameRef) or it could be a wildcard reference like "*.example.com", which is not a DNSNameRef. Thus we need a new type, something like:

enum PresentedDNSIDRef<'a> {
    DNSName(DNSNameRef<'a>),
    Wildcard(untrusted::Input<'a>),
}

Then GeneralName::DNSName(untrusted::Input) can be changed to GeneralName::DNSName(PresentedDNSID).

Note that this might cause us to recognize invalid DNS names earlier and we should be sure not to change our current behavior (whether it is skipping invalid DNS names or aborting the operation upon an invalid DNS name; I've forgotten).

Remove support for RSA PKCS#1 1.5 signatures without the NULL parameters

Right now RSA PKCS#1 1.5 signatures are the only ones where we support two encodings of the Algorithmidentifier: one with a NULL parameter and one without any parameters. RFC 4055 requires CAs to only use the form with the NULL parameter. While it also requires implementations to accept both forms, accepting only form form would allow us to simplify the signature algorithm matching significantly.

To do this, we should get some estimate of how common non-conformant certificates (without the NULL parameters) are.

Allow all integers for trust anchor serial numbers

72a3ad9 made parsing serial numbers reject zero and negative serial numbers. There are a few such root certificates in mozilla's and debian's root certs:

subject= /C=EU/O=AC Camerfirma SA CIF A82743287/OU=http://www.chambersign.org/CN=Chambers of Commerce Root
serial=00
subject= /C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc./CN=Go Daddy Root Certificate Authority - G2
serial=00
subject= /C=US/ST=Arizona/L=Scottsdale/O=Starfield Technologies, Inc./CN=Starfield Root Certificate Authority - G2
serial=00
subject= /C=US/ST=Arizona/L=Scottsdale/O=Starfield Technologies, Inc./CN=Starfield Services Root Certificate Authority - G2
serial=00
subject= /C=EU/O=AC Camerfirma SA CIF A82743287/OU=http://www.chambersign.org/CN=Global Chambersign Root
serial=00
subject= /C=ES/O=Agencia Catalana de Certificacio (NIF Q-0801176-I)/OU=Serveis Publics de Certificacio/OU=Vegeu https://www.catcert.net/verarrel (c)03/OU=Jerarquia Entitats de Certificacio Catalanes/CN=EC-ACC
serial=-11D4C2142BDE21EB579D53FB0C223BFF
subject= /C=US/O=The Go Daddy Group, Inc./OU=Go Daddy Class 2 Certification Authority
serial=00
subject= /C=GR/O=Hellenic Academic and Research Institutions Cert. Authority/CN=Hellenic Academic and Research Institutions RootCA 2011
serial=00
subject= /C=JP/O=SECOM Trust Systems CO.,LTD./OU=Security Communication EV RootCA1
serial=00
subject= /C=JP/O=SECOM Trust Systems CO.,LTD./OU=Security Communication RootCA2
serial=00
subject= /C=JP/O=SECOM Trust.net/OU=Security Communication RootCA1
serial=00
subject= /C=US/O=Starfield Technologies, Inc./OU=Starfield Class 2 Certification Authority
serial=00

These are technically incorrect and most are of questionable value, but aws.amazon.com roots to Starfield Class 2 Certification Authority and wordpress.com roots to Go Daddy Root Certificate Authority - G2.

Create an indexing system for efficiently selecting a cert chain given client SNI when there are many possible certificate chains to choose from.

See #64, #67, #68, and #70 for background. Basically when a TLS terminator is doing TLS for a lot of different hostnames, it will have a lot of certificates to manage. In #64 @Geal mentioned that he has built an indexing system for efficiently determining which certificate chain to use based on information from the ClientHello. We should build such a mechanism into webpki.

verify_cert_dns_name appears only to work against subjectAltName

I have the following cert:

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 456 (0x1c8)
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN=ponytown level 2 intermediate
        Validity
            Not Before: May 20 21:59:24 2016 GMT
            Not After : Jun 19 21:59:24 2016 GMT
        Subject: CN=testserver.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:da:99:b5:76:7b:ff:18:2f:61:02:17:62:a4:80:
                    58:21:cc:01:81:0c:71:9f:3c:08:5e:19:8a:5e:fb:
                    db:6d:66:67:34:c2:e6:b9:30:f6:b1:8d:91:87:23:
                    e1:4f:a4:76:6c:fe:89:c3:03:b6:a0:3c:f2:22:84:
                    1b:b2:2b:b4:8b:59:23:f3:23:04:19:64:fc:53:4d:
                    d2:7e:fe:f8:32:b4:68:4c:29:34:aa:0d:33:e9:87:
                    72:38:e3:80:44:90:f4:2e:0b:6f:4c:f9:9a:3b:d2:
                    76:d3:b7:69:92:e1:60:1d:2a:90:62:85:7c:e2:10:
                    3c:12:1f:b4:61:77:32:b2:d0:2b:13:b8:57:89:53:
                    2d:f2:35:75:28:32:0f:9e:1c:d4:6b:bb:86:cf:10:
                    36:eb:df:24:f7:84:fe:84:94:da:49:d7:a2:c2:2f:
                    e4:ad:37:7f:55:55:f3:80:01:95:81:be:ea:31:02:
                    9e:c5:c8:1f:a2:c8:42:39:a1:0a:a3:80:9a:46:b8:
                    ab:55:4a:9d:71:d7:b8:4a:03:f0:f7:aa:10:a2:34:
                    dc:cd:04:1f:34:57:4c:ac:b3:3b:dc:a2:1a:6b:73:
                    e7:65
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Basic Constraints: critical
                CA:FALSE
            X509v3 Key Usage: 
                Digital Signature, Non Repudiation
            X509v3 Subject Key Identifier: 
                91:4F:84:13:A5:69:3C:3B:F0:7D:78:34:74:DC:55:F0:90:34:BF:9E
            X509v3 Authority Key Identifier: 
                keyid:EC:DA:EF:92:48:28:07:D4:E2:6C:84:E2:60:96:57:49:4F:36:A2:C4
                DirName:/CN=ponytown CA
                serial:7B

    Signature Algorithm: sha256WithRSAEncryption
         11:3b:dc:12:c9:75:ad:fa:76:38:8e:9d:5c:eb:43:2d:4d:22:
         92:45:f9:a4:be:4e:c7:b6:92:30:de:ed:ac:35:97:55:48:5a:
         c6:49:0a:90:11:e2:5a:c4:88:17:85:cd:72:6f:0e:9f:fe:79:
         11:ee:ec:ef:7f:c7:91:ec:90:d2:e0:49:94:2e:d8:95:80:b0:
         3d:22:80:fd:79:20:2c:56:44:45:99:e7:75:e0:61:81:eb:36:
         47:26:b5:61:dc:85:80:c9:79:13:b6:75:b9:44:d0:2f:f3:b5:
         8e:1e:92:d6:5a:a2:9c:bf:d5:82:5d:1a:17:b1:ac:9c:97:86:
         07:0c:b9:0f:fd:bb:3b:91:fb:9b:cf:14:43:c1:84:97:ca:67:
         3f:d7:f8:ac:05:47:61:aa:fe:94:e8:dd:84:77:77:5e:0c:cd:
         96:37:f9:24:73:8b:2f:49:fd:82:89:a0:f0:21:02:d3:cb:95:
         8c:96:73:7c:60:c8:87:58:5f:eb:96:f1:25:d3:5c:4a:42:97:
         d3:ad:5d:2b:9b:a8:06:7c:85:93:4e:0e:9c:9a:c9:3a:99:f8:
         f0:9d:76:82:47:56:79:67:40:62:d3:65:5f:8f:de:c5:04:44:
         ab:89:d4:58:fb:38:c6:9d:63:36:c6:13:58:8e:24:f1:48:5b:
         8c:e0:89:91:ea:91:6c:af:86:4e:22:e0:49:69:37:51:9d:ac:
         36:f4:29:8d:d7:b9:32:fd:b4:73:e7:06:2d:bc:97:5d:4d:0f:
         50:20:1d:42:f5:04:a3:03:7e:0b:9e:29:c5:88:1f:c9:c9:8a:
         c1:fe:b8:50:99:4f:b4:11:50:3a:f6:d4:68:58:10:3c:72:97:
         6d:5d:67:f1:fb:64:26:36:c7:3b:f1:24:25:f1:7c:84:63:8f:
         e2:d5:bb:a5:c8:8d:17:4b:c5:22:e4:df:f4:51:47:0e:2c:a0:
         89:84:f9:22:38:4b:e3:f6:f2:d1:da:7a:f6:35:a1:35:63:2c:
         7e:d8:fb:6c:b7:ed
-----BEGIN CERTIFICATE-----
MIIDuTCCAiGgAwIBAgICAcgwDQYJKoZIhvcNAQELBQAwKDEmMCQGA1UEAwwdcG9u
eXRvd24gbGV2ZWwgMiBpbnRlcm1lZGlhdGUwHhcNMTYwNTIwMjE1OTI0WhcNMTYw
NjE5MjE1OTI0WjAZMRcwFQYDVQQDDA50ZXN0c2VydmVyLmNvbTCCASIwDQYJKoZI
hvcNAQEBBQADggEPADCCAQoCggEBANqZtXZ7/xgvYQIXYqSAWCHMAYEMcZ88CF4Z
il77221mZzTC5rkw9rGNkYcj4U+kdmz+icMDtqA88iKEG7IrtItZI/MjBBlk/FNN
0n7++DK0aEwpNKoNM+mHcjjjgESQ9C4Lb0z5mjvSdtO3aZLhYB0qkGKFfOIQPBIf
tGF3MrLQKxO4V4lTLfI1dSgyD54c1Gu7hs8QNuvfJPeE/oSU2knXosIv5K03f1VV
84ABlYG+6jECnsXIH6LIQjmhCqOAmka4cF9lEfCAbrmnRLpaUiOOXLcmHxi/e+TC
03TjFTn4q1VKnXHXuEoD8PeqEKI03M0EHzRXTKyzO9yiGmtz52UCAwEAAaN8MHow
DAYDVR0TAQH/BAIwADALBgNVHQ8EBAMCBsAwHQYDVR0OBBYEFJFPhBOlaTw78H14
NHTcVfCQNL+eMD4GA1UdIwQ3MDWAFOza75JIKAfU4myE4mCWV0lPNqLEoRqkGDAW
MRQwEgYDVQQDDAtwb255dG93biBDQYIBezANBgkqhkiG9w0BAQsFAAOCAYEAETvc
Esl1rfp2OI6dXOtDLU0ikkX5pL5Ox7aSMN7trDWXVUhaxkkKkBHiWsSIF4XNcm8O
n/55Ee7s73/HkeyQ0uBJlC7YlYCwPSKA/XkgLFZERZnndeBhges2Rya1YdyFgMl5
E7Z1uUTQL/O1jh6S1lqinL/Vgl0aF7GsnJeGBwy5D/27O5H7m88UQ8GEl8pnP9f4
rAVHYar+lOjdhHd3XgzNljf5JHOLL0n9gomg8CEC08uVjJZzfGDIh1hf65bxJdNc
SkKX061dK5uoBnyFk04OnJrJOpn48J12gkdWeWdAYtNlX4/exQREq4nUWPs4xp1j
NsYTWI4k8UhbjOCJkeqRbK+GTiLgSWk3UZ2sNvQpjde5Mv20c+cGLbyXXU0PUCAd
QvUEowN+C54pxYgfycmKwf64UJlPtBFQOvbUaFgQPHKXbV1n8ftkJjbHO/EkJfF8
hGOP4tW7pciNF0vFIuTf9FFHDiygiYT5IjhL4/by0dp69jWhNWMsftj7bLft
-----END CERTIFICATE-----

I'd expect verify_cert_dns_name to say Ok to that for the input "testserver.com", but it says CertNotValidForName.

Here's a minimal test program:

extern crate webpki;
extern crate ring;

fn main() {
  let bytes = vec![
    0x30, 0x82, 0x03, 0xb9, 0x30, 0x82, 0x02, 0x21, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x02, 0x01,
    0xc8, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00,
    0x30, 0x28, 0x31, 0x26, 0x30, 0x24, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1d, 0x70, 0x6f, 0x6e,
    0x79, 0x74, 0x6f, 0x77, 0x6e, 0x20, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x20, 0x32, 0x20, 0x69, 0x6e,
    0x74, 0x65, 0x72, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36,
    0x30, 0x35, 0x32, 0x30, 0x32, 0x31, 0x35, 0x39, 0x32, 0x34, 0x5a, 0x17, 0x0d, 0x31, 0x36, 0x30,
    0x36, 0x31, 0x39, 0x32, 0x31, 0x35, 0x39, 0x32, 0x34, 0x5a, 0x30, 0x19, 0x31, 0x17, 0x30, 0x15,
    0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65,
    0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
    0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01,
    0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xda, 0x99, 0xb5, 0x76, 0x7b, 0xff, 0x18, 0x2f, 0x61, 0x02,
    0x17, 0x62, 0xa4, 0x80, 0x58, 0x21, 0xcc, 0x01, 0x81, 0x0c, 0x71, 0x9f, 0x3c, 0x08, 0x5e, 0x19,
    0x8a, 0x5e, 0xfb, 0xdb, 0x6d, 0x66, 0x67, 0x34, 0xc2, 0xe6, 0xb9, 0x30, 0xf6, 0xb1, 0x8d, 0x91,
    0x87, 0x23, 0xe1, 0x4f, 0xa4, 0x76, 0x6c, 0xfe, 0x89, 0xc3, 0x03, 0xb6, 0xa0, 0x3c, 0xf2, 0x22,
    0x84, 0x1b, 0xb2, 0x2b, 0xb4, 0x8b, 0x59, 0x23, 0xf3, 0x23, 0x04, 0x19, 0x64, 0xfc, 0x53, 0x4d,
    0xd2, 0x7e, 0xfe, 0xf8, 0x32, 0xb4, 0x68, 0x4c, 0x29, 0x34, 0xaa, 0x0d, 0x33, 0xe9, 0x87, 0x72,
    0x38, 0xe3, 0x80, 0x44, 0x90, 0xf4, 0x2e, 0x0b, 0x6f, 0x4c, 0xf9, 0x9a, 0x3b, 0xd2, 0x76, 0xd3,
    0xb7, 0x69, 0x92, 0xe1, 0x60, 0x1d, 0x2a, 0x90, 0x62, 0x85, 0x7c, 0xe2, 0x10, 0x3c, 0x12, 0x1f,
    0xb4, 0x61, 0x77, 0x32, 0xb2, 0xd0, 0x2b, 0x13, 0xb8, 0x57, 0x89, 0x53, 0x2d, 0xf2, 0x35, 0x75,
    0x28, 0x32, 0x0f, 0x9e, 0x1c, 0xd4, 0x6b, 0xbb, 0x86, 0xcf, 0x10, 0x36, 0xeb, 0xdf, 0x24, 0xf7,
    0x84, 0xfe, 0x84, 0x94, 0xda, 0x49, 0xd7, 0xa2, 0xc2, 0x2f, 0xe4, 0xad, 0x37, 0x7f, 0x55, 0x55,
    0xf3, 0x80, 0x01, 0x95, 0x81, 0xbe, 0xea, 0x31, 0x02, 0x9e, 0xc5, 0xc8, 0x1f, 0xa2, 0xc8, 0x42,
    0x39, 0xa1, 0x0a, 0xa3, 0x80, 0x9a, 0x46, 0xb8, 0x70, 0x5f, 0x65, 0x11, 0xf0, 0x80, 0x6e, 0xb9,
    0xa7, 0x44, 0xba, 0x5a, 0x52, 0x23, 0x8e, 0x5c, 0xb7, 0x26, 0x1f, 0x18, 0xbf, 0x7b, 0xe4, 0xc2,
    0xd3, 0x74, 0xe3, 0x15, 0x39, 0xf8, 0xab, 0x55, 0x4a, 0x9d, 0x71, 0xd7, 0xb8, 0x4a, 0x03, 0xf0,
    0xf7, 0xaa, 0x10, 0xa2, 0x34, 0xdc, 0xcd, 0x04, 0x1f, 0x34, 0x57, 0x4c, 0xac, 0xb3, 0x3b, 0xdc,
    0xa2, 0x1a, 0x6b, 0x73, 0xe7, 0x65, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x7c, 0x30, 0x7a, 0x30,
    0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0b, 0x06,
    0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x06, 0xc0, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d,
    0x0e, 0x04, 0x16, 0x04, 0x14, 0x91, 0x4f, 0x84, 0x13, 0xa5, 0x69, 0x3c, 0x3b, 0xf0, 0x7d, 0x78,
    0x34, 0x74, 0xdc, 0x55, 0xf0, 0x90, 0x34, 0xbf, 0x9e, 0x30, 0x3e, 0x06, 0x03, 0x55, 0x1d, 0x23,
    0x04, 0x37, 0x30, 0x35, 0x80, 0x14, 0xec, 0xda, 0xef, 0x92, 0x48, 0x28, 0x07, 0xd4, 0xe2, 0x6c,
    0x84, 0xe2, 0x60, 0x96, 0x57, 0x49, 0x4f, 0x36, 0xa2, 0xc4, 0xa1, 0x1a, 0xa4, 0x18, 0x30, 0x16,
    0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0b, 0x70, 0x6f, 0x6e, 0x79, 0x74,
    0x6f, 0x77, 0x6e, 0x20, 0x43, 0x41, 0x82, 0x01, 0x7b, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
    0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x81, 0x00, 0x11, 0x3b, 0xdc,
    0x12, 0xc9, 0x75, 0xad, 0xfa, 0x76, 0x38, 0x8e, 0x9d, 0x5c, 0xeb, 0x43, 0x2d, 0x4d, 0x22, 0x92,
    0x45, 0xf9, 0xa4, 0xbe, 0x4e, 0xc7, 0xb6, 0x92, 0x30, 0xde, 0xed, 0xac, 0x35, 0x97, 0x55, 0x48,
    0x5a, 0xc6, 0x49, 0x0a, 0x90, 0x11, 0xe2, 0x5a, 0xc4, 0x88, 0x17, 0x85, 0xcd, 0x72, 0x6f, 0x0e,
    0x9f, 0xfe, 0x79, 0x11, 0xee, 0xec, 0xef, 0x7f, 0xc7, 0x91, 0xec, 0x90, 0xd2, 0xe0, 0x49, 0x94,
    0x2e, 0xd8, 0x95, 0x80, 0xb0, 0x3d, 0x22, 0x80, 0xfd, 0x79, 0x20, 0x2c, 0x56, 0x44, 0x45, 0x99,
    0xe7, 0x75, 0xe0, 0x61, 0x81, 0xeb, 0x36, 0x47, 0x26, 0xb5, 0x61, 0xdc, 0x85, 0x80, 0xc9, 0x79,
    0x13, 0xb6, 0x75, 0xb9, 0x44, 0xd0, 0x2f, 0xf3, 0xb5, 0x8e, 0x1e, 0x92, 0xd6, 0x5a, 0xa2, 0x9c,
    0xbf, 0xd5, 0x82, 0x5d, 0x1a, 0x17, 0xb1, 0xac, 0x9c, 0x97, 0x86, 0x07, 0x0c, 0xb9, 0x0f, 0xfd,
    0xbb, 0x3b, 0x91, 0xfb, 0x9b, 0xcf, 0x14, 0x43, 0xc1, 0x84, 0x97, 0xca, 0x67, 0x3f, 0xd7, 0xf8,
    0xac, 0x05, 0x47, 0x61, 0xaa, 0xfe, 0x94, 0xe8, 0xdd, 0x84, 0x77, 0x77, 0x5e, 0x0c, 0xcd, 0x96,
    0x37, 0xf9, 0x24, 0x73, 0x8b, 0x2f, 0x49, 0xfd, 0x82, 0x89, 0xa0, 0xf0, 0x21, 0x02, 0xd3, 0xcb,
    0x95, 0x8c, 0x96, 0x73, 0x7c, 0x60, 0xc8, 0x87, 0x58, 0x5f, 0xeb, 0x96, 0xf1, 0x25, 0xd3, 0x5c,
    0x4a, 0x42, 0x97, 0xd3, 0xad, 0x5d, 0x2b, 0x9b, 0xa8, 0x06, 0x7c, 0x85, 0x93, 0x4e, 0x0e, 0x9c,
    0x9a, 0xc9, 0x3a, 0x99, 0xf8, 0xf0, 0x9d, 0x76, 0x82, 0x47, 0x56, 0x79, 0x67, 0x40, 0x62, 0xd3,
    0x65, 0x5f, 0x8f, 0xde, 0xc5, 0x04, 0x44, 0xab, 0x89, 0xd4, 0x58, 0xfb, 0x38, 0xc6, 0x9d, 0x63,
    0x36, 0xc6, 0x13, 0x58, 0x8e, 0x24, 0xf1, 0x48, 0x5b, 0x8c, 0xe0, 0x89, 0x91, 0xea, 0x91, 0x6c,
    0xaf, 0x86, 0x4e, 0x22, 0xe0, 0x49, 0x69, 0x37, 0x51, 0x9d, 0xac, 0x36, 0xf4, 0x29, 0x8d, 0xd7,
    0xb9, 0x32, 0xfd, 0xb4, 0x73, 0xe7, 0x06, 0x2d, 0xbc, 0x97, 0x5d, 0x4d, 0x0f, 0x50, 0x20, 0x1d,
    0x42, 0xf5, 0x04, 0xa3, 0x03, 0x7e, 0x0b, 0x9e, 0x29, 0xc5, 0x88, 0x1f, 0xc9, 0xc9, 0x8a, 0xc1,
    0xfe, 0xb8, 0x50, 0x99, 0x4f, 0xb4, 0x11, 0x50, 0x3a, 0xf6, 0xd4, 0x68, 0x58, 0x10, 0x3c, 0x72,
    0x97, 0x6d, 0x5d, 0x67, 0xf1, 0xfb, 0x64, 0x26, 0x36, 0xc7, 0x3b, 0xf1, 0x24, 0x25, 0xf1, 0x7c,
    0x84, 0x63, 0x8f, 0xe2, 0xd5, 0xbb, 0xa5, 0xc8, 0x8d, 0x17, 0x4b, 0xc5, 0x22, 0xe4, 0xdf, 0xf4,
    0x51, 0x47, 0x0e, 0x2c, 0xa0, 0x89, 0x84, 0xf9, 0x22, 0x38, 0x4b, 0xe3, 0xf6, 0xf2, 0xd1, 0xda,
    0x7a, 0xf6, 0x35, 0xa1, 0x35, 0x63, 0x2c, 0x7e, 0xd8, 0xfb, 0x6c, 0xb7, 0xed
  ];

  let input = ring::input::Input::new(&bytes).unwrap();
  let name = ring::input::Input::new("testserver.com".as_bytes()).unwrap();
  let rc = webpki::verify_cert_dns_name(input, name);
  println!("rc = {:?}", rc);
}

I think the issue is a missing match of GeneralName::DirectoryName in the closure given to iterate_names.

Cut 0.18.0 release

Would be good to get rustls trunk back to depending on crates builds of everything.

Replace AlgorithmIdentifier parsing with bytewise comparison

Depending on the results of #25 and #30, we'll hopefully be able to get rid of all the parsing of AlgorithmIdentifiers in favor of just matching them as byte strings. The reduction in code size should offset the increase in data size for most size-conscious applications, which probably only need to support the subset of the algorithms recommended in the TLS 1.3 specification.

Source of BadDER

Hello,

In some test code I'm using locally generated certificates. When I try to connect to a service using one of these certificates I'm getting the error BadDER. Unfortunately that's all I can seem to get, and when looking at the code it seems these could be generated in one of many places.

Is there any way to narrow down exactly what went wrong?

Support perfect-hash-based trust anchor lookup

In order to scale to a large number of trust anchors, it may be worthwhile to use rust-phf or similar to look up the trust anchor very quickly for static sets of trust anchors like webpki-roots.

EndEntityCert::verify_is_valid_tls_server_cert takes a trust_anchors: &[TrustAnchor] parameter. Presumably we'd change that to something like trust_anchors: &[&TrustAnchorMap], where TrustAnchorMap is something like:

pub trait TrustAnchorMap {
    fn get(issuer_name_der_value: &[u8]) -> Option<&TrustAnchor>,
}

pub struct TrustAnchorArrayMap(&[TrustAnchor]);

impl TrustAnchorMap for TrustAnchorArrayMap {
    fn get(&self, issuer_name_der_value: &[u8]) -> Option<&TrustAnchor> {
        // Do a linear search like we currently do.
   }
}

struct TrustAnchorHashMap {
    // whatever the rust-pfh implementation generates.
}

impl TrustAnchorMap for TrustAnchorHashMap {
    fn get(&self, issuer_name_der_value: &[u8]) -> Option<&TrustAnchor> {
        // Calculate the hash using the function rust-phf generates,
        // then lookup the `TrustAnchor` in an array by the resultant
        // index.
   }
}

Ideally we'd not need to do this, as it seems awfully complicated and we only need to “scale” to ~200 trust anchors, for which it seems like a linear search would work fine. We likely can optimize the linear search to have acceptable performance. And first, we need to verify that this is actually a bottleneck by resolving #38. Just recording this idea so it doesn't get lost.

[Question] How does webpki decide if a common name is a DirectoryName instead of DNSName?

I have the common name my_controller_1.server which is failing cert validation because webpki thinks it's a name::GeneralName::DirectoryName instead of a name::GeneralName::DNSName when it's doing verification in name::verify_cert_dns_name.

How does webpki decide if a name like my_controller_1.server is a DirectoryName or a DNSName? As far as I can tell that could be a legitimate DNS name (I don't think it violates RFC6125).

Is verification inefficient when there are many trust anchors?

In rustls/rustls#47 (comment), @avadacatavra published some numbers that showed that doing a bunch of signature verifications in parallel (each with only one trust anchor?) was significantly faster than doing a single verification with a large number of trust anchors (from https://github.com/ctz/webpki-roots?). The point of this issue is to investigate why that is the case, and identify potential solutions.

rustls/rustls#47 (comment) lists 13 sites that are being used by the Servo project to benchmark performance. I think it should be straightforward to extract the certificate chains they are sending and build a benchmark using those certificate chains + webpki-roots, but which is independent of a TLS stack, to get a rough idea of what the issues are, regardless of whether we think that corpus is the right one for us to optimize for.

Using the benchmark, we should be able to profile performance and find out the issue.

Speculation: webpki wasn't really written with the expectation that a large number of trust anchors would be used. Instead, it was originally designed for embedded applications which would have only a few trust anchors. webpki contains an optimization for trying to build a short chain, which is simply looping over the trust anchors before looping over the given intermediates. This is a linear search, which is reasonable if the number of trust anchors is small, but maybe not if the number of trust anchors isn't small. If the profile shows that the match loop_while_non_fatal_error(trust_anchors, expression is taking a significant amount of time (note: it may be easier to see this if each loop_while_non_fatal_error(... call is factored out into its own function), then we can optimize that. For example, we could use https://github.com/sfackler/rust-phf to replace the linear search with a hash table lookup, if webpki-roots would be willing to implement a new API based on that.

@avadacatavra Is my description of your measurements (using webpki-roots as the root store, and benchmarking many threads using 1 trust anchor vs. 1 thread using all of the trust anchors in webpki-roots) accurate?

/cc @ctz

Self signed CAfile are rejected

Maybe I'm missing something, but self-signed CAfile are accepted by openssl, while being rejected by webpki. Steps to reproduce (using rustls):

$ curl http://test.mosquitto.org/ssl/mosquitto.org.crt -O
$ openssl s_client -connect test.mosquitto.org:8883 -CAfile mosquitto.org.crt
[...]
Verify return code: 0 (ok)
[...]
$ echo "" | cargo run --example tlsclient -- --cafile mosquitto.org.crt -p 8883 --verbose test.mosquitto.org
[...]
TLS error: WebPKIError(UnknownIssuer)
[...]

As far as I can tell, the failing test is the one here https://github.com/briansmith/webpki/blob/master/src/verify_cert.rs#L91 .

Add API for verifying that a private key is valid for a certificate

TLS servers, and TLS clients that do client authentication, need way to verify that a private key that they're about to use for authentication is the one that corresponds to the certificate they present to the peer. And/or they need an API that selects a certificate that matches a private key.

See *ring issue 419 for more context.

@ctz Do you have any suggestions for an API that you could use in Rustls to verify that the certificate and the private key being used are consistent?

There is no way to construct the optimum certificate chain

Consider a server that has one or more end-entity certificates for a given hostname (e.g. ClientHello SNI value). Each end-entity certificate might have multiple valid certificate chains due to cross-signing and/or due to overlapping validity periods when CAs renew their CA certificates. The server can only return one certificate chain in the TLS handshake. Which one should it return?

Right now, webpki uses some simple heuristics to construct a valid certificate chain. It doesn't really put significant effort into building the "best" chain. So far, this seems to have generally sufficed for the purposes of web browsers (see the record of mozilla::pkix in Firefox, for example) but it isn't ideal for some server use cases.

Unfortunately it isn't clear that there is agreement on how to determine which certificate chain is best. If there is some agreement then it definitely makes sense to just implement the rules for selecting the best cert in webpki. If there's disagreement, then we might need to make the selection mechanism more flexible. Regardless, I think there's a lot of value in centralizing as much of the "best certificate chain" logic in webpki as we can.

See Cloudflare's CFSSL, which has implemented similar logic, to some extent.

Here are some of the criteria I'm most familiar with, which are relevant to certificate chain selection:

All else being equal, a certificate chain that is smaller in terms of bytes on the wire is better than a certificate chain that is larger.

All else being equal, a certificate chain that is shorter in terms of number of intermediate certificates is better than a certificate chain that is longer.

All else being equal, a certificate chain that isn't just about to become invalid due to certificate expiration is better than one that's just about to expire.

All else being equal, the server would prefer to use a certificate with a public key associated with a private key that uses an algorithm that is faster to sign with, vs. one that is slower to sign with.

All else being equal, the server would prefer to use a certificate with a public key associated with a private key that is highly protected (e.g. in a HSM) vs one that isn't as highly protected.

All else being equal, the server would prefer to use a certificate for which it has valid SCT proofs, stapled OCSP responses, etc. vs one for which it is missing those things.

All else being equal, the server would prefer to use a certificate chain that has a trust anchor that is most likely to be trusted by the client.

Refactor public verification API into a state machine

Right now there are three steps involved in verifying a peer's certificate chain, as documented at https://briansmith.org/rustdoc/webpki/struct.EndEntityCert.html. Instead of telling people that they need to do all three steps, we should provide an API that doesn't give a "yes, valid" answer until all three steps have been done.

The tricky part is that we want to support these steps being done in parallel and/or out of the natural order, for performance reasons. The interaction between coordinating the parallel tasks and avoding dynamic memory allocation could make this tricky.

Also, we may want to have two state machines: One for verifying a peer's identity, and another for verifying our own identity, which is like identifying a peer's identity as well as checking that the cert is consistent with our private key.

webpki/cert: extend `verify_is_valid_for` to iPAddress SAN

I currently have some certificates from a private CA where the subject identity is established via an iPAddress subject alternative name. I just checked that this crate only tries to match a dNSName against a CN or a SAN, which is the reason why validation fails. This is a feature request to add support for such SAN validation.

As I (or somebody else) may want to tackle this in the future, I'd like to get some input on the expected API for this:

  • should a new dedicated is_valid_for_ip be introduced?
  • should the current is_valid_for_dns be renamed/overloaded to accept more than one SAN types?
  • should the consumer call is_valid_for multiple times, or just once with all DNSs/IPs/etc?
  • should the Ok return type be amended to return back the matching entry?

What's the API of other TLS library in this regard? Should this crate stick to prior art?

(I was personally thinking about a single is_valid_for which takes a slice of subject names, and returns back the matching one on success)

Allow v1 root certs to be used with `trust_anchor_util::cert_der_as_trust_anchor`

Apparently Netflix sometimes uses a certificate that chains to a X509v1 root: https://github.com/ctz/webpki/blob/c79b35d6d1fd37ccb34c7e9d9efb9b2c412a35bb/tests/netflix/ca.der. So, it's probably necessary to have trust_anchor_util::cert_der_as_trust_anchor parse such certificates.

But, the other code (path building in particular) shouldn't accept v1 certs as either end-entity or CA certificates.

@ctz already fixed this in his branch: ctz@4763aac.

Return the constructed certificate chain during verification

Some applications need to remember the certificate chain that was constructed during validation. This can be accomplished by having verify_is_valid_tls_server_cert(), verify_is_valid_tls_client_cert(), etc., return the constructed certificate chain.

We want certificate validation to be possible even in a heap-less #![no_std] environment so we cannot return the certificate chain as a Vec. Instead we need to use a type like ArrayVec that is guaranteed to never use the heap.

Note that we already maintain what is effectively a linked list in the child_cert fields, so it's basically just a matter of converting this linked list into an ArrayVec-like thing.

Verify signatures in parallel

All the signature verification for a cert chain is in the function check_signatures. By replacing the loop in that function with a parallel loop, we'll do all the signature verification in parallel. This would be a significant win when there are multiple cores available because signature verification is the most expensive (as far as we know) part of certificate chain validation.

Basically, replace the current loop with one that collects the signatures from the linked list of Certs into an ArrayVec with capacity 1 + MAX_SUB_CA_COUNT + 1. Then verify the signatures by iterating over the ArrayVec in parallel. (Don't Vec because we don't allow memory allocation in this crate.)

I guess rayon and jobsteal and similar crates do use dynamic memory allocation and so can't work in #![no_std] configurations. Assuming that is the case, we can add a use_std default feature that enables the use of rayon/jobsteal/whatever. When the use_std feature is disabled, let's use the same code looping code, but use a single-threaded polyfill for rayon/jobsteal/whatever.

EndEntityCert::verify_is_valid_tls_server_cert should take an an input parameter a reference to the thread pool object that is configured by the caller. In particular, the caller should configure the thread pool before calling verify_is_valid_tls_server_cert() to control how resources (how many threads) are used, so that webpki itself doesn't need to have any options for this.

Allow using the end-entity public key for verifying signatures

Currently we don't provide access to the end-entity public key, so one cannot verify signatures (or do RSA decryption) using the public key. Thus, one can't implement TLS and other protocols on top of webpki.

Further, many IETF protocols and data formats use the common SignedData sub-structure for signed data. So, it would be useful to have access for SignedData and maybe parse_signed_data or some variant of it.

See @ctz's attempt at ctz@7ac0381

Consider handling of certificates for localhost

A CA-signed TLS cert for localhost sounds rather strange. I can think of a few use cases, all of which involve a certificate generated just for the given machine.

In particular, I can't think of any reason for any CA that is not special-purpose to be creating certificates for localhost.

Add u2f attestation support

  • Add support for U2F trust anchors.
  • Make it easy to parse the u2f attestation certificate out of the U2F message.
  • Maybe add a workaround for the encoding issue described at #34 (comment).
  • Write documentation, including an example, about how to verify attestations.
  • Compare AAGUID from the certificate via the id-fido-gen-ce-aaguid extension and comparing it to the expected AAGUID.
  • Packed Attestation Certificates
    • Don't require a subjectAltName extension.
  • TPM Attestation Certificates
    • Subject must be empty
    • There must be a SAN as specified in the TPM specs.
    • EKU = "2.23.133.8.3" OID.
  • Android Attestation Certificates
    • dNSName = attest.android.com

AFAICT, Yubico's attestation certificates don't include any EKU or key usage fields. Presumably we shouldn't verify for an EKU and the key usage should be digitalSignature.

/cc @wisespace-io @robn

try_from_* methods should either return an error-containing Result or an Option

Considering the following DNSNameRef signatures

pub fn try_from_ascii(dns_name: untrusted::Input<'a>) -> Result<Self, ()> {
pub fn try_from_ascii_str(dns_name: &str) -> Result<DNSNameRef, ()> {

From an API standpoint, I think returning a Result that has () for an error type is not good design.

If multiple libraries adopt this pattern, it is not possible to differentiate between the () from lib A and () from lib B. Which forces any error to be map_err() / handled immediately by the calling code when most often a simple ? would be preferable. It would otherwise be preposterous to force applications to assume that any () error result originates only from webpki, or to require that any error of type () be considered of unknown origin.

If a Result<> has no error context to provide, an error-less Option<> should be returned instead.

Remove SHA-1 support

Remove the following signature algorithms:

  • ECDSA_P256_SHA1
  • ECDSA_P384_SHA1
  • RSA_PKCS1_2048_8192_SHA1

Mozilla, Microsoft, and Google are all planning to turn off SHA-1 support on 2017-1-1 or 2017-2-1. It seems unlikely that anybody using webpki is going to need to support SHA-1 even as of now, so I propose we remove them now.

Provide a way to get the validity time period for an `EndEntityCert`

When a server is terminating TLS for many logical servers with lots of different DNS names it will need to manage a lot of certificates. When the number of certificates becomes large the server needs to create an index to find which certificate chain (and private key) to use, given the SNI from the ClientHello message.

Besides being able to extract all the DNS names from the certificates to build the index, the server also needs to know when each certificate would expire so that it can rotate in another configuration before the expiration occurs.

The most thorough way to accomplish this would be for the server to validate the certificate and calculate the max(notBefore) and min(notAfter) times for the chain. That would require the certificate to know the valid set of trust anchors and it would require the server to have all the intermediate certificates present.

The simplest way to accomplish this is to assume that the end-entity certificates always expire before any of the CA certificates that issue them expire. This isn't a valid assumption in general, however.

/cc @Geal.

Considering only checking for duplicate keys in a chain to prevent loops

Currently, we have code like:

if potential_issuer.spki == prev.spki &&
   potential_issuer.subject == prev.subject {
    return Err(Error::UnknownIssuer);
}

Ilari Liusvaara suggested that it is enough to prevent the duplicate keys, without bothering to check for duplicate names. We should experiment with that.

Note: The above code assumes that that only the canonical (true DER) form of SPKIs is accepted, and no variants are accepted.

Enforce maximum validity period length

Allow the caller to specify a maximum validity length and offer a suggested default value based on what was decided in the CAB Forum and/or Mozilla and/or other policy discussions. Then reject any certificates where notAfter - notBefore > that validity period length.

get rfc822Name/email from certificate's SAN?

I don't see a way to get an email address out of a certificate's subject_alternate_name. Is that something that webpki could support? I think this is related to #64.

I have client certificates from which I want to get the email after verification is successful. Today I'm using openssl like this but I'm trying to avoid that dependency.

It is possible to DoS certificate validation with name constraints and/or a large number of candidate intermediates

There is a DoS attack exploits the fact that name constraint checking, in particular, has quardratic (at least) behavior. If certificate A that chains to a certificate B and certificate A has a lot of names and certificate B has a lot of name constraints, then we do a lot of checking. BoringSSL's solution was to verify that the entire certificate chain is valid modulo name constraints, and then check name constraints. (TODO: verify that this summary of what they did is accurate.) We should do that or something better.

#68 might make this easier to do; regardless this and #68 interact with each other.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.