[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: gnutls fails to use Verisign CA cert without a Basic Constraint
From: |
Douglas E. Engert |
Subject: |
Re: gnutls fails to use Verisign CA cert without a Basic Constraint |
Date: |
Thu, 08 Jan 2009 11:35:00 -0600 |
User-agent: |
Thunderbird 2.0.0.19 (Windows/20081209) |
Attached are the server cert (auth2.it.anl.gov), the intermediate cert
(f0a38a80.0)
and the CA self signed cert (7651b327.0) a debug version of verify.c
and partial output of an ldapsearch using the debug.c
My patch has been #if 0'ed out at line 151.
Lets refer to the cert chain as A, B and C. The OpenLDAP server (using OpenSSL)
sends server cert A, intermediate cert B, and CA cert C.
The TLS_CACERT file has B and C.
The clist_size is then 3, and the code in _gnutls_x509_verify_certificate
around lines 443 drop it to 2, leaving the chain as A, B.
The tcase_size is 2.
_gnutls_verify_certificate2 at line 452 is called with cert B and
tcas with B and C and flags 0.
At line 265, find_issuer is called with B. It returns C.
check_is_ca is called at line 297, which fails
because there is no BasicConstraint. The if at 293 looks correct too.
*BUT* if one trusts both B and C, do we need to verify C?
Why does the code arount line 265 not stop after finding that B is in the tcas,
rather then looking for C, and then verifying it?
If I try it again with the TLS_CACERT file with only B,
it also fails because it can not find the issuer of B.
If the code around line 265 was modified if B was found in the tcas,
this shopuld also work.
Simon Josefsson wrote:
"Douglas E. Engert" <address@hidden> writes:
This is also being submitted to https://bugs.launchpad.net/bugs
Using the Ubuntu version of libgnutls13_2.0.4-1ubuntu2.3 on Hardy 8.04.1,
ldaps: has stopped working. This looks like it is related to
the December changes that are also in gnutls-2.6.3. See attached
patch that should work in both.
ldapsearch -d 1 -H ldaps://...
TLS: peer cert untrusted or revoked (0x82)
ldap_err2string
ldap_sasl_bind(SIMPLE): Can't contact LDAP server (-1)
The OpenLDAP ldap server certificate issued by Verisign is signed by:
Verisign_Intermediate-Secure_Site_Managed_PKI_for_SSL_Standard_Certificates.pem
which is signed by:
Verisign_Class_3_Public_Primary_Certification_Authority.pem
Both of these are in /etc/ssl/certs as 7651b327.0 and f0a38a80.0
Verisign_Class_3_Public_Primary_Certification_Authority.pem
is a self signed version 1 cert issued in 1996, with no extensions.
Do you have a complete chain that triggers this? It will help our
regression test suite.
I don't have f0a38a80.0 on my debian lenny system. Does it also lack a
basicConstraint? Does it use RSA-MDx? If yes, that would explain the
problem.
In lib/x509/verify.c gnutls_x509_crt_get_ca_status is called
but returns GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE as there is no
Basic Constraint.
The attached patch (to gnutls13_2.0.4-1ubuntu2.3) checks for
this return and if it is a self signed cert, will treat it as a CA.
The patch looks like it can be applied to 2.6.3 as well.
The patch seems too permissive to me: the intention is that V1 certs
should be rejected by GnuTLS unless GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT
and/or GNUTLS_VERIFY_ALLOW_ANY_X509_V1_CA_CRT are passed as flags.
Internally, GnuTLS by default enables the
GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT flag when called via
gnutls_certificate_verify_peers2. So I think GnuTLS should typically
accept this chain.
Indeed, looking at the code that invokes the function you patched:
if (!(flags & GNUTLS_VERIFY_DISABLE_CA_SIGN) &&
!((flags & GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT) && issuer_version == 1))
{
if (check_if_ca (cert, issuer, flags) == 0)
{
gnutls_assert ();
if (output)
*output |= GNUTLS_CERT_SIGNER_NOT_CA | GNUTLS_CERT_INVALID;
return 0;
}
}
It seems that the code you patched should not have been invoked at all
if (flags & GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT) && issuer_version == 1
is true (if I understand the logic correctly..). Could you debug why
this isn't the case? Maybe issuer_version is wrong?
A complete chain to reproduce this will let me debug it too.
/Simon
Clients on Solaris 9 and 10, and OpenLDAP using OpenSSL on any
platform have no problems with this old cert.
--
Douglas E. Engert <address@hidden>
Argonne National Laboratory
9700 South Cass Avenue
Argonne, Illinois 60439
(630) 252-5444
--- ,verify.c 2009-01-06 14:02:41.000000000 -0600
+++ verify.c 2009-01-07 17:07:27.000000000 -0600
@@ -130,11 +130,20 @@
}
}
- if (gnutls_x509_crt_get_ca_status (issuer, NULL) == 1)
+ result = gnutls_x509_crt_get_ca_status (issuer, NULL);
+ if (result == 1)
{
result = 1;
goto cleanup;
}
+ /* Old self signed CA certs may not have basic constrant */
+ else if ((result == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) &&
+ (gnutls_x509_crt_check_issuer(issuer, issuer) == 1))
+ {
+ gnutls_assert ();
+ result = 1;
+ goto cleanup;
+ }
else
gnutls_assert ();
_______________________________________________
Gnutls-devel mailing list
address@hidden
http://lists.gnu.org/mailman/listinfo/gnutls-devel
--
Douglas E. Engert <address@hidden>
Argonne National Laboratory
9700 South Cass Avenue
Argonne, Illinois 60439
(630) 252-5444
-----BEGIN CERTIFICATE-----
MIIEnDCCBAWgAwIBAgIQdTN9mrDhIzuuLX3kRpFi1DANBgkqhkiG9w0BAQUFADBf
MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsT
LkNsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw
HhcNMDUwMTE5MDAwMDAwWhcNMTUwMTE4MjM1OTU5WjCBsDELMAkGA1UEBhMCVVMx
FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz
dCBOZXR3b3JrMTswOQYDVQQLEzJUZXJtcyBvZiB1c2UgYXQgaHR0cHM6Ly93d3cu
dmVyaXNpZ24uY29tL3JwYSAoYykwNTEqMCgGA1UEAxMhVmVyaVNpZ24gQ2xhc3Mg
MyBTZWN1cmUgU2VydmVyIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
AQEAlcMhEo5AxQ0BX3ZeZpTZcyxYGSK4yfx6OZAqd3J8HT732FXjr0LLhzAC3Fus
cOa4RLQrNeuT0hcFfstG1lxToDJRnXRkWPkMmgDqXkRJZHL0zRDihQr5NO6ziGap
paRa0A6Yf1gNK1K7hql+LvqySHyN2y1fAXWijQY7i7RhB8m+Ipn4G9G1V2YETTX0
kXGWtZkIJZuXyDrzILHdnpgMSmO3ps6wAc74k2rzDG6fsemEe4GYQeaB3D0s57Rr
4578CBbXs9W5ZhKZfG1xyE2+xw/j+zet1XWHIWuG0EQUWlR5OZZpVsm5Mc2JYVjh
2XYFBa33uQKvp/1HkaIiNFox0QIDAQABo4IBgTCCAX0wEgYDVR0TAQH/BAgwBgEB
/wIBADBEBgNVHSAEPTA7MDkGC2CGSAGG+EUBBxcDMCowKAYIKwYBBQUHAgEWHGh0
dHBzOi8vd3d3LnZlcmlzaWduLmNvbS9ycGEwMQYDVR0fBCowKDAmoCSgIoYgaHR0
cDovL2NybC52ZXJpc2lnbi5jb20vcGNhMy5jcmwwDgYDVR0PAQH/BAQDAgEGMBEG
CWCGSAGG+EIBAQQEAwIBBjApBgNVHREEIjAgpB4wHDEaMBgGA1UEAxMRQ2xhc3Mz
Q0EyMDQ4LTEtNDUwHQYDVR0OBBYEFG/sr6DdiqTv9SoQZy0/VYK81+8lMIGABgNV
HSMEeTB3oWOkYTBfMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIElu
Yy4xNzA1BgNVBAsTLkNsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlv
biBBdXRob3JpdHmCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQEFBQADgYEA
w34IRl2RNs9n3Nenr6+4IsOLBHTTsWC85v63RBKBWzFzFGNWxnIu0RoDQ1w4ClBK
Tc3athmo9JkNr+P32PF1KGX2av6b9L1S2T/L2hbLpZ4ujmZSeD0m+v6UNohKlV4q
TBnvbvqCPy0D79YoszcYz0KyNCFkR9MgazpM3OYDkAw=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIE/zCCA+egAwIBAgIQBSsgZODO6vk6ayagofBQJDANBgkqhkiG9w0BAQUFADCB
sDELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTswOQYDVQQLEzJUZXJtcyBvZiB1c2Ug
YXQgaHR0cHM6Ly93d3cudmVyaXNpZ24uY29tL3JwYSAoYykwNTEqMCgGA1UEAxMh
VmVyaVNpZ24gQ2xhc3MgMyBTZWN1cmUgU2VydmVyIENBMB4XDTA4MDUwNTAwMDAw
MFoXDTA5MDUyMjIzNTk1OVowczELMAkGA1UEBhMCVVMxETAPBgNVBAgTCElsbGlu
b2lzMRAwDgYDVQQHFAdEdSBQYWdlMSQwIgYDVQQKFBtBcmdvbm5lIE5hdGlvbmFs
IExhYm9yYXRvcnkxGTAXBgNVBAMUEGF1dGgyLml0LmFubC5nb3YwgZ8wDQYJKoZI
hvcNAQEBBQADgY0AMIGJAoGBAMg6YPOXsPQedkLUug3RoMjv/OB+SfuDgGXxtef5
iE0SjCcsKT5v+bfxt2+ccs7IN7kWn1luJ5NTb0ZrdE6LQoYp9oLsaX/ukOnxKUMY
YhJJyHgutPtwyPvfZTZPpATWycJnZGIehY1S6thwxeofUyE3ykec2lalULzwXgel
iC97AgMBAAGjggHTMIIBzzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIFoDBEBgNVHR8E
PTA7MDmgN6A1hjNodHRwOi8vU1ZSU2VjdXJlLWNybC52ZXJpc2lnbi5jb20vU1ZS
U2VjdXJlMjAwNS5jcmwwRAYDVR0gBD0wOzA5BgtghkgBhvhFAQcXAzAqMCgGCCsG
AQUFBwIBFhxodHRwczovL3d3dy52ZXJpc2lnbi5jb20vcnBhMB0GA1UdJQQWMBQG
CCsGAQUFBwMBBggrBgEFBQcDAjAfBgNVHSMEGDAWgBRv7K+g3Yqk7/UqEGctP1WC
vNfvJTB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLnZl
cmlzaWduLmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL1NWUlNlY3VyZS1haWEudmVy
aXNpZ24uY29tL1NWUlNlY3VyZTIwMDUtYWlhLmNlcjBuBggrBgEFBQcBDARiMGCh
XqBcMFowWDBWFglpbWFnZS9naWYwITAfMAcGBSsOAwIaBBRLa7kolgYMu9BSOJsp
rEsHiyEFGDAmFiRodHRwOi8vbG9nby52ZXJpc2lnbi5jb20vdnNsb2dvMS5naWYw
DQYJKoZIhvcNAQEFBQADggEBAEAKzE4gXeyjRDBSgAgWIaCozbWK+b1ct4aZhWZt
ihAyASxsNgDjDJzkInINjXoO5FWuJHDuoyyWHBQBb7t96+KgFu/4ye90VUDNTuin
mmqdOKeLSHVnlhfvGLCdrhWSWg/jZmAjYrXYRwkvxehl9IcHmOgNrHV3INdrSTdZ
ZCVLL74tuMqhMMm/NJ0tdEmWgpJe+/0dky2F2gAB+mFXlyzFvCLoyS2Vl0PW/BxM
Ly5t+scmAbgni9gzmFTNhbKHd0s2UE395z4ra6fUdZ0BClFgMDvUnb6kJ/uyKRSa
h7uQbWFJbA8aNgGLvfTf6o9n+GwbZkcgtBgIVENt8wzqg2I=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzEL
MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQL
Ey5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y
aXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UE
BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz
cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGf
MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69q
RUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94f56TuZoAqiN91qyFomNFx3In
zPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Olhec9vn2a
/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBAgUAA4GBALtM
EivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Dolbwdj2wsqFHMc9ikwFPw
TtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNycAA9WjQKZ7aKQRUzk
uxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k
-----END CERTIFICATE-----
DEE _gnutls_x509_verify_certificate:418 clist_size=3
DEE _gnutls_x509_verify_certificate:434 cert: subject `C=US,O=VeriSign\,
Inc.,OU=Class 3 Public Primary Certification Authority', issuer
`C=US,O=VeriSign\, Inc.,OU=Class 3 Public Primary Certification Authority', RSA
key 1024 bits, activated `1996-01-29 00:00:00 UTC', expires `2028-08-01
23:59:59 UTC', SHA-1 fingerprint `742c3192e607e424eb4549542be1bbc53e6174e2'
DEE _gnutls_x509_verify_certificate:438 clist_size=3
ASSERT: verify.c:442
DEE _gnutls_x509_verify_certificate:447 clist_size=2
DEE _gnutls_x509_verify_certificate:454 tcas_size=2 flags=0x0
DEE _gnutls_verify_certificate2 flags=0x0
DEE _gnutls_verify_certificate2:292 flags=0x0 issuer_version=1
DEE _gnutls_verify_certificate2:296
ASSERT: x509.c:2095
DEE check_if_ca:136 flag=0x0 checking issuer cert:
X.509 Certificate Information:
Version: 1
Serial Number (hex): 70bae41d10d92934b638ca7b03ccbabf
Issuer: C=US,O=VeriSign\, Inc.,OU=Class 3 Public Primary Certification
Authority
Validity:
Not Before: Mon Jan 29 00:00:00 UTC 1996
Not After: Tue Aug 1 23:59:59 UTC 2028
Subject: C=US,O=VeriSign\, Inc.,OU=Class 3 Public Primary Certification
Authority
Subject Public Key Algorithm: RSA
Modulus (bits 1024):
c9:5c:59:9e:f2:1b:8a:01:14:b4:10:df:04:40:db:e3
57:af:6a:45:40:8f:84:0c:0b:d1:33:d9:d9:11:cf:ee
02:58:1f:25:f7:2a:a8:44:05:aa:ec:03:1f:78:7f:9e
93:b9:9a:00:aa:23:7d:d6:ac:85:a2:63:45:c7:72:27
cc:f4:4c:c6:75:71:d2:39:ef:4f:42:f0:75:df:0a:90
c6:8e:20:6f:98:0f:f8:ac:23:5f:70:29:36:a4:c9:86
e7:b1:9a:20:cb:53:a5:85:e7:3d:be:7d:9a:fe:24:45
33:dc:76:15:ed:0f:a2:71:64:4c:65:2e:81:68:45:a7
Exponent:
01:00:01
Signature Algorithm: RSA-MD2
warning: signed using a broken signature algorithm that can be forged.
Signature:
bb:4c:1ASSERT: verify.c:150
DEE check_if_ca:163 result=-56
DEE check_is_ca result=0
ASSERT: dn.c:298
ASSERT: x509.c:1025
ASSERT: x509.c:753
ASSERT: x509.c:2095
DEE failed cert:
X.509 Certificate Information:
Version: 3
Serial Number (hex): 75337d9ab0e1233bae2d7de4469162d4
Issuer: C=US,O=VeriSign\, Inc.,OU=Class 3 Public Primary Certification
Authority
Validity:
Not Before: Wed Jan 19 00:00:00 UTC 2005
Not After: Sun Jan 18 23:59:59 UTC 2015
Subject: C=US,O=VeriSign\, Inc.,OU=VeriSign Trust Network,OU=Terms of
use at https://www.verisign.com/rpa (c)05,CN=VeriSign Class 3 Secure Server CA
Subject Public Key Algorithm: RSA
Modulus (bits 2048):
95:c3:21:12:8e:40:c5:0d:01:5f:76:5e:66:94:d9:73
2c:58:19:22:b8:c9:fc:7a:39:90:2a:77:72:7c:1d:3e
f7:d8:55:e3:af:42:cb:87:30:02:dc:5b:ac:70:e6:b8
44:b4:2b:35:eb:93:d2:17:05:7e:cb:46:d6:5c:53:a0
32:51:9d:74:64:58:f9:0c:9a:00:ea:5e:44:49:64:72
f4:cd:10:e2:85:0a:f9:34:ee:b3:88:66:a9:a5:a4:5a
d0:0e:98:7f:58:0d:2b:52:bb:86:a9:7e:2e:fa:b2:48
7c:8d:db:2d:5f:01:75:a2:8d:06:3b:8b:b4:61:07:c9
be:22:99:f8:1b:d1:b5:57:66:04:4d:35:f4:91:71:96
b5:99:08:25:9b:97:c8:3a:f3:20:b1:dd:9e:98:0c:4a
63:b7:a6ASSERT: x509.c:2095
DEE failed issuer:
X.509 Certificate Information:
Version: 1
Serial Number (hex): 70bae41d10d92934b638ca7b03ccbabf
Issuer: C=US,O=VeriSign\, Inc.,OU=Class 3 Public Primary Certification
Authority
Validity:
Not Before: Mon Jan 29 00:00:00 UTC 1996
Not After: Tue Aug 1 23:59:59 UTC 2028
Subject: C=US,O=VeriSign\, Inc.,OU=Class 3 Public Primary Certification
Authority
Subject Public Key Algorithm: RSA
Modulus (bits 1024):
c9:5c:59:9e:f2:1b:8a:01:14:b4:10:df:04:40:db:e3
57:af:6a:45:40:8f:84:0c:0b:d1:33:d9:d9:11:cf:ee
02:58:1f:25:f7:2a:a8:44:05:aa:ec:03:1f:78:7f:9e
93:b9:9a:00:aa:23:7d:d6:ac:85:a2:63:45:c7:72:27
cc:f4:4c:c6:75:71:d2:39:ef:4f:42:f0:75:df:0a:90
c6:8e:20:6f:98:0f:f8:ac:23:5f:70:29:36:a4:c9:86
e7:b1:9a:20:cb:53:a5:85:e7:3d:be:7d:9a:fe:24:45
33:dc:76:15:ed:0f:a2:71:64:4c:65:2e:81:68:45:a7
Exponent:
01:00:01
Signature Algorithm: RSA-MD2
warning: signed using a broken signature algorithm that can be forged.
Signature:
bb:4c:12:2b:cf:2c:26:00:4f:14:13:dd:a6:ASSERT: verify.c:307
DEE ret=0
ASSERT: verify.c:466
TLS: peer cert untrusted or revoked (0x82)
ldap_err2string
ldap_sasl_bind(SIMPLE): Can't contact LDAP server (-1)
/*
* Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation
*
* Author: Nikos Mavroyanopoulos
*
* This file is part of GNUTLS.
*
* The GNUTLS library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA
*
*/
/* All functions which relate to X.509 certificate verification stuff are
* included here
*/
#include <gnutls_int.h>
#include <gnutls_errors.h>
#include <gnutls_cert.h>
#include <libtasn1.h>
#include <gnutls_global.h>
#include <gnutls_num.h> /* MAX */
#include <gnutls_sig.h>
#include <gnutls_str.h>
#include <gnutls_datum.h>
#include <dn.h>
#include <x509.h>
#include <mpi.h>
#include <common.h>
#include <verify.h>
static int _gnutls_verify_certificate2 (gnutls_x509_crt_t cert,
const gnutls_x509_crt_t * trusted_cas,
int tcas_size, unsigned int flags,
unsigned int *output);
int _gnutls_x509_verify_signature (const gnutls_datum_t * signed_data,
const gnutls_datum_t * signature,
gnutls_x509_crt_t issuer);
static
int is_crl_issuer (gnutls_x509_crl_t crl, gnutls_x509_crt_t issuer_cert);
static int _gnutls_verify_crl2 (gnutls_x509_crl_t crl,
const gnutls_x509_crt_t * trusted_cas,
int tcas_size, unsigned int flags,
unsigned int *output);
/* Checks if the issuer of a certificate is a
* Certificate Authority, or if the certificate is the same
* as the issuer (and therefore it doesn't need to be a CA).
*
* Returns true or false, if the issuer is a CA,
* or not.
*/
static int
check_if_ca (gnutls_x509_crt_t cert, gnutls_x509_crt_t issuer,
unsigned int flags)
{
gnutls_datum_t cert_signed_data = { NULL, 0 };
gnutls_datum_t issuer_signed_data = { NULL, 0 };
gnutls_datum_t cert_signature = { NULL, 0 };
gnutls_datum_t issuer_signature = { NULL, 0 };
int result;
/* Check if the issuer is the same with the
* certificate. This is added in order for trusted
* certificates to be able to verify themselves.
*/
result =
_gnutls_x509_get_signed_data (issuer->cert, "tbsCertificate",
&issuer_signed_data);
if (result < 0)
{
gnutls_assert ();
goto cleanup;
}
result =
_gnutls_x509_get_signed_data (cert->cert, "tbsCertificate",
&cert_signed_data);
if (result < 0)
{
gnutls_assert ();
goto cleanup;
}
result =
_gnutls_x509_get_signature (issuer->cert, "signature", &issuer_signature);
if (result < 0)
{
gnutls_assert ();
goto cleanup;
}
result =
_gnutls_x509_get_signature (cert->cert, "signature", &cert_signature);
if (result < 0)
{
gnutls_assert ();
goto cleanup;
}
/* If the subject certificate is the same as the issuer
* return true.
*/
if (!(flags & GNUTLS_VERIFY_DO_NOT_ALLOW_SAME))
if (cert_signed_data.size == issuer_signed_data.size)
{
if ((memcmp (cert_signed_data.data, issuer_signed_data.data,
cert_signed_data.size) == 0) &&
(cert_signature.size == issuer_signature.size) &&
(memcmp (cert_signature.data, issuer_signature.data,
cert_signature.size) == 0))
{
result = 1;
goto cleanup;
}
}
{
gnutls_datum_t out;
gnutls_x509_crt_print(issuer, GNUTLS_X509_CRT_FULL, &out);
_gnutls_debug_log("DEE %s:%d flag=0x%x checking issuer cert:\n%s\n",
__FUNCTION__,__LINE__,flags,out.data);
gnutls_free (out.data);
}
if ((result=gnutls_x509_crt_get_ca_status (issuer, NULL)) == 1)
{
result = 1;
goto cleanup;
}
else
{
/* if the cert has no basic constraint, and it is self signed,
* treat as a CA
*/
gnutls_assert ();
#if 0
if (result == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE &&
gnutls_x509_crt_check_issuer( issuer, issuer) == 1)
{
gnutls_assert ();
result = 1;
goto cleanup;
}
#endif
}
_gnutls_debug_log("DEE %s:%d result=%d\n",__FUNCTION__,__LINE__,result);
result = 0;
cleanup:
_gnutls_free_datum (&cert_signed_data);
_gnutls_free_datum (&issuer_signed_data);
_gnutls_free_datum (&cert_signature);
_gnutls_free_datum (&issuer_signature);
_gnutls_debug_log("DEE check_is_ca result=%d\n",result);
return result;
}
/* This function checks if 'certs' issuer is 'issuer_cert'.
* This does a straight (DER) compare of the issuer/subject fields in
* the given certificates.
*
* Returns 1 if they match and zero if they don't match. Otherwise
* a negative value is returned to indicate error.
*/
static int
is_issuer (gnutls_x509_crt_t cert, gnutls_x509_crt_t issuer_cert)
{
gnutls_datum_t dn1 = { NULL, 0 }, dn2 =
{
NULL, 0};
int ret;
ret = gnutls_x509_crt_get_raw_issuer_dn (cert, &dn1);
if (ret < 0)
{
gnutls_assert ();
goto cleanup;
}
ret = gnutls_x509_crt_get_raw_dn (issuer_cert, &dn2);
if (ret < 0)
{
gnutls_assert ();
goto cleanup;
}
ret = _gnutls_x509_compare_raw_dn (&dn1, &dn2);
cleanup:
_gnutls_free_datum (&dn1);
_gnutls_free_datum (&dn2);
return ret;
}
static inline gnutls_x509_crt_t
find_issuer (gnutls_x509_crt_t cert,
const gnutls_x509_crt_t * trusted_cas, int tcas_size)
{
int i;
/* this is serial search.
*/
for (i = 0; i < tcas_size; i++)
{
if (is_issuer (cert, trusted_cas[i]) == 1)
return trusted_cas[i];
}
gnutls_assert ();
return NULL;
}
/*
* Verifies the given certificate again a certificate list of
* trusted CAs.
*
* Returns only 0 or 1. If 1 it means that the certificate
* was successfuly verified.
*
* 'flags': an OR of the gnutls_certificate_verify_flags enumeration.
*
* Output will hold some extra information about the verification
* procedure.
*/
static int
_gnutls_verify_certificate2 (gnutls_x509_crt_t cert,
const gnutls_x509_crt_t * trusted_cas,
int tcas_size, unsigned int flags,
unsigned int *output)
{
gnutls_datum_t cert_signed_data = { NULL, 0 };
gnutls_datum_t cert_signature = { NULL, 0 };
gnutls_x509_crt_t issuer;
int ret, issuer_version, result;
_gnutls_debug_log("DEE _gnutls_verify_certificate2 flags=0x%x\n",flags);
if (output)
*output = 0;
if (tcas_size >= 1)
issuer = find_issuer (cert, trusted_cas, tcas_size);
else
{
gnutls_assert ();
if (output)
*output |= GNUTLS_CERT_SIGNER_NOT_FOUND | GNUTLS_CERT_INVALID;
return 0;
}
/* issuer is not in trusted certificate
* authorities.
*/
if (issuer == NULL)
{
if (output)
*output |= GNUTLS_CERT_SIGNER_NOT_FOUND | GNUTLS_CERT_INVALID;
gnutls_assert ();
return 0;
}
issuer_version = gnutls_x509_crt_get_version (issuer);
if (issuer_version < 0)
{
gnutls_assert ();
return issuer_version;
}
_gnutls_debug_log("DEE %s:%d flags=0x%x
issuer_version=%d\n",__FUNCTION__,__LINE__,flags,issuer_version);
if (!(flags & GNUTLS_VERIFY_DISABLE_CA_SIGN) &&
!((flags & GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT) && issuer_version == 1))
{
_gnutls_debug_log("DEE %s:%d\n",__FUNCTION__,__LINE__);
if (check_if_ca (cert, issuer, flags) == 0)
{
gnutls_datum_t out;
gnutls_x509_crt_print(cert, GNUTLS_X509_CRT_FULL, &out);
_gnutls_debug_log("DEE failed cert:\n%s\n", out.data);
gnutls_free (out.data);
gnutls_x509_crt_print(issuer, GNUTLS_X509_CRT_FULL, &out);
_gnutls_debug_log("DEE failed issuer:\n%s\n", out.data);
gnutls_free (out.data);
gnutls_assert ();
if (output)
*output |= GNUTLS_CERT_SIGNER_NOT_CA | GNUTLS_CERT_INVALID;
return 0;
}
}
result =
_gnutls_x509_get_signed_data (cert->cert, "tbsCertificate",
&cert_signed_data);
if (result < 0)
{
gnutls_assert ();
goto cleanup;
}
result =
_gnutls_x509_get_signature (cert->cert, "signature", &cert_signature);
if (result < 0)
{
gnutls_assert ();
goto cleanup;
}
ret =
_gnutls_x509_verify_signature (&cert_signed_data, &cert_signature,
issuer);
if (ret < 0)
{
gnutls_assert ();
}
else if (ret == 0)
{
gnutls_assert ();
/* error. ignore it */
if (output)
*output |= GNUTLS_CERT_INVALID;
ret = 0;
}
/* If the certificate is not self signed check if the algorithms
* used are secure. If the certificate is self signed it doesn't
* really matter.
*/
if (is_issuer (cert, cert) == 0)
{
int sigalg;
sigalg = gnutls_x509_crt_get_signature_algorithm (cert);
if (((sigalg == GNUTLS_SIGN_RSA_MD2) &&
!(flags & GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD2)) ||
((sigalg == GNUTLS_SIGN_RSA_MD5) &&
!(flags & GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5)))
{
if (output)
*output |= GNUTLS_CERT_INSECURE_ALGORITHM | GNUTLS_CERT_INVALID;
}
}
result = ret;
cleanup:
_gnutls_free_datum (&cert_signed_data);
_gnutls_free_datum (&cert_signature);
return result;
}
/**
* gnutls_x509_crt_check_issuer - This function checks if the certificate
given has the given issuer
* @cert: is the certificate to be checked
* @issuer: is the certificate of a possible issuer
*
* This function will check if the given certificate was issued by the
* given issuer. It will return true (1) if the given certificate is issued
* by the given issuer, and false (0) if not.
*
* A negative value is returned in case of an error.
*
**/
int
gnutls_x509_crt_check_issuer (gnutls_x509_crt_t cert,
gnutls_x509_crt_t issuer)
{
return is_issuer (cert, issuer);
}
/* The algorithm used is:
* 1. Check last certificate in the chain. If it is not verified return.
* 2. Check if any certificates in the chain are revoked. If yes return.
* 3. Try to verify the rest of certificates in the chain. If not verified
return.
* 4. Return 0.
*
* Note that the return value is an OR of GNUTLS_CERT_* elements.
*
* This function verifies a X.509 certificate list. The certificate list should
* lead to a trusted CA in order to be trusted.
*/
static unsigned int
_gnutls_x509_verify_certificate (const gnutls_x509_crt_t * certificate_list,
int clist_size,
const gnutls_x509_crt_t * trusted_cas,
int tcas_size,
const gnutls_x509_crl_t * CRLs,
int crls_size, unsigned int flags)
{
int i = 0, ret;
unsigned int status = 0, output;
_gnutls_debug_log("DEE %s:%d
clist_size=%d\n",__FUNCTION__,__LINE__,clist_size);
if (clist_size > 1)
{
/* Check if the last certificate in the path is self signed.
* In that case ignore it (a certificate is trusted only if it
* leads to a trusted party by us, not the server's).
*
* This in addition prevents from verifying self signed certificates
* against themselves. This although not bad caused verification
* failures on some root self signed certificates that use the MD2
* algorithm.
*/
{
gnutls_datum_t out;
gnutls_x509_crt_print(certificate_list[clist_size - 1],
GNUTLS_X509_CRT_ONELINE, &out);
_gnutls_debug_log("DEE %s:%d cert: %s\n",
__FUNCTION__,__LINE__,out.data);
gnutls_free (out.data);
}
_gnutls_debug_log("DEE %s:%d
clist_size=%d\n",__FUNCTION__,__LINE__,clist_size);
if (gnutls_x509_crt_check_issuer (certificate_list[clist_size - 1],
certificate_list[clist_size - 1]) > 0)
{
gnutls_assert ();
clist_size--;
}
}
_gnutls_debug_log("DEE %s:%d
clist_size=%d\n",__FUNCTION__,__LINE__,clist_size);
/* Verify the last certificate in the certificate path
* against the trusted CA certificate list.
*
* If no CAs are present returns CERT_INVALID. Thus works
* in self signed etc certificates.
*/
_gnutls_debug_log("DEE %s:%d tcas_size=%d
flags=0x%x\n",__FUNCTION__,__LINE__,tcas_size, flags);
ret =
_gnutls_verify_certificate2 (certificate_list[clist_size - 1],
trusted_cas, tcas_size, flags, &output);
_gnutls_debug_log("DEE ret=%d\n",ret);
if (ret == 0)
{
/* if the last certificate in the certificate
* list is invalid, then the certificate is not
* trusted.
*/
gnutls_assert ();
status |= output;
status |= GNUTLS_CERT_INVALID;
return status;
}
/* Check for revoked certificates in the chain
*/
#ifdef ENABLE_PKI
for (i = 0; i < clist_size; i++)
{
{
gnutls_datum_t out;
gnutls_x509_crt_print(certificate_list[i], GNUTLS_X509_CRT_ONELINE,
&out);
_gnutls_debug_log("DEE %s:%d cert: %s\n",
__FUNCTION__,__LINE__,out.data);
gnutls_free (out.data);
}
ret = gnutls_x509_crt_check_revocation (certificate_list[i],
CRLs, crls_size);
if (ret == 1)
{ /* revoked */
status |= GNUTLS_CERT_REVOKED;
status |= GNUTLS_CERT_INVALID;
return status;
}
}
#endif
/* Verify the certificate path (chain)
*/
for (i = clist_size - 1; i > 0; i--)
{
if (i - 1 < 0)
break;
/* note that here we disable this V1 CA flag. So that no version 1
* certificates can exist in a supplied chain.
*/
if (!(flags & GNUTLS_VERIFY_ALLOW_ANY_X509_V1_CA_CRT))
flags ^= GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT;
{
gnutls_datum_t out;
gnutls_x509_crt_print(certificate_list[i-1], GNUTLS_X509_CRT_ONELINE,
&out);
_gnutls_debug_log("DEE %s:%d cert: %s\n",
__FUNCTION__,__LINE__,out.data);
gnutls_free (out.data);
gnutls_x509_crt_print(certificate_list[i], GNUTLS_X509_CRT_ONELINE,
&out);
_gnutls_debug_log("DEE %s:%d cert: %s\n",
__FUNCTION__,__LINE__,out.data);
gnutls_free (out.data);
}
if ((ret =
_gnutls_verify_certificate2 (certificate_list[i - 1],
&certificate_list[i], 1, flags,
NULL)) == 0)
{
gnutls_assert ();
status |= GNUTLS_CERT_INVALID;
return status;
}
}
gnutls_assert ();
return 0;
}
/* Reads the digest information.
* we use DER here, although we should use BER. It works fine
* anyway.
*/
static int
decode_ber_digest_info (const gnutls_datum_t * info,
gnutls_mac_algorithm_t * hash,
opaque * digest, int *digest_size)
{
ASN1_TYPE dinfo = ASN1_TYPE_EMPTY;
int result;
char str[1024];
int len;
if ((result = asn1_create_element (_gnutls_get_gnutls_asn (),
"GNUTLS.DigestInfo",
&dinfo)) != ASN1_SUCCESS)
{
gnutls_assert ();
return _gnutls_asn2err (result);
}
result = asn1_der_decoding (&dinfo, info->data, info->size, NULL);
if (result != ASN1_SUCCESS)
{
gnutls_assert ();
asn1_delete_structure (&dinfo);
return _gnutls_asn2err (result);
}
len = sizeof (str) - 1;
result = asn1_read_value (dinfo, "digestAlgorithm.algorithm", str, &len);
if (result != ASN1_SUCCESS)
{
gnutls_assert ();
asn1_delete_structure (&dinfo);
return _gnutls_asn2err (result);
}
*hash = _gnutls_x509_oid2mac_algorithm (str);
if (*hash == GNUTLS_MAC_UNKNOWN)
{
_gnutls_x509_log ("verify.c: HASH OID: %s\n", str);
gnutls_assert ();
asn1_delete_structure (&dinfo);
return GNUTLS_E_UNKNOWN_HASH_ALGORITHM;
}
len = sizeof (str) - 1;
result = asn1_read_value (dinfo, "digestAlgorithm.parameters", str, &len);
/* To avoid permitting garbage in the parameters field, either the
parameters field is not present, or it contains 0x05 0x00. */
if (!(result == ASN1_ELEMENT_NOT_FOUND ||
(result == ASN1_SUCCESS && len == 2 &&
str[0] == 0x05 && str[1] == 0x00)))
{
gnutls_assert ();
asn1_delete_structure (&dinfo);
return GNUTLS_E_ASN1_GENERIC_ERROR;
}
result = asn1_read_value (dinfo, "digest", digest, digest_size);
if (result != ASN1_SUCCESS)
{
gnutls_assert ();
asn1_delete_structure (&dinfo);
return _gnutls_asn2err (result);
}
asn1_delete_structure (&dinfo);
return 0;
}
/* if hash==MD5 then we do RSA-MD5
* if hash==SHA then we do RSA-SHA
* params[0] is modulus
* params[1] is public key
*/
static int
_pkcs1_rsa_verify_sig (const gnutls_datum_t * text,
const gnutls_datum_t * signature, mpi_t * params,
int params_len)
{
gnutls_mac_algorithm_t hash = GNUTLS_MAC_UNKNOWN;
int ret;
opaque digest[MAX_HASH_SIZE], md[MAX_HASH_SIZE];
int digest_size;
GNUTLS_HASH_HANDLE hd;
gnutls_datum_t decrypted;
ret =
_gnutls_pkcs1_rsa_decrypt (&decrypted, signature, params, params_len, 1);
if (ret < 0)
{
gnutls_assert ();
return ret;
}
/* decrypted is a BER encoded data of type DigestInfo
*/
digest_size = sizeof (digest);
if ((ret =
decode_ber_digest_info (&decrypted, &hash, digest, &digest_size)) != 0)
{
gnutls_assert ();
_gnutls_free_datum (&decrypted);
return ret;
}
_gnutls_free_datum (&decrypted);
if (digest_size != _gnutls_hash_get_algo_len (hash))
{
gnutls_assert ();
return GNUTLS_E_ASN1_GENERIC_ERROR;
}
hd = _gnutls_hash_init (hash);
if (hd == NULL)
{
gnutls_assert ();
return GNUTLS_E_HASH_FAILED;
}
_gnutls_hash (hd, text->data, text->size);
_gnutls_hash_deinit (hd, md);
if (memcmp (md, digest, digest_size) != 0)
{
gnutls_assert ();
return GNUTLS_E_PK_SIG_VERIFY_FAILED;
}
return 0;
}
/* Hashes input data and verifies a DSA signature.
*/
static int
dsa_verify_sig (const gnutls_datum_t * text,
const gnutls_datum_t * signature, mpi_t * params,
int params_len)
{
int ret;
opaque _digest[MAX_HASH_SIZE];
gnutls_datum_t digest;
GNUTLS_HASH_HANDLE hd;
hd = _gnutls_hash_init (GNUTLS_MAC_SHA1);
if (hd == NULL)
{
gnutls_assert ();
return GNUTLS_E_HASH_FAILED;
}
_gnutls_hash (hd, text->data, text->size);
_gnutls_hash_deinit (hd, _digest);
digest.data = _digest;
digest.size = 20;
ret = _gnutls_dsa_verify (&digest, signature, params, params_len);
return ret;
}
/* Verifies the signature data, and returns 0 if not verified,
* or 1 otherwise.
*/
static int
verify_sig (const gnutls_datum_t * tbs,
const gnutls_datum_t * signature,
gnutls_pk_algorithm_t pk, mpi_t * issuer_params,
int issuer_params_size)
{
switch (pk)
{
case GNUTLS_PK_RSA:
if (_pkcs1_rsa_verify_sig
(tbs, signature, issuer_params, issuer_params_size) != 0)
{
gnutls_assert ();
return 0;
}
return 1;
break;
case GNUTLS_PK_DSA:
if (dsa_verify_sig
(tbs, signature, issuer_params, issuer_params_size) != 0)
{
gnutls_assert ();
return 0;
}
return 1;
break;
default:
gnutls_assert ();
return GNUTLS_E_INTERNAL_ERROR;
}
}
/* verifies if the certificate is properly signed.
* returns 0 on failure and 1 on success.
*
* 'tbs' is the signed data
* 'signature' is the signature!
*/
int
_gnutls_x509_verify_signature (const gnutls_datum_t * tbs,
const gnutls_datum_t * signature,
gnutls_x509_crt_t issuer)
{
mpi_t issuer_params[MAX_PUBLIC_PARAMS_SIZE];
int ret, issuer_params_size, i;
/* Read the MPI parameters from the issuer's certificate.
*/
issuer_params_size = MAX_PUBLIC_PARAMS_SIZE;
ret =
_gnutls_x509_crt_get_mpis (issuer, issuer_params, &issuer_params_size);
if (ret < 0)
{
gnutls_assert ();
return ret;
}
ret =
verify_sig (tbs, signature,
gnutls_x509_crt_get_pk_algorithm (issuer, NULL),
issuer_params, issuer_params_size);
if (ret < 0)
{
gnutls_assert ();
}
/* release all allocated MPIs
*/
for (i = 0; i < issuer_params_size; i++)
{
_gnutls_mpi_release (&issuer_params[i]);
}
return ret;
}
/* verifies if the certificate is properly signed.
* returns 0 on failure and 1 on success.
*
* 'tbs' is the signed data
* 'signature' is the signature!
*/
int
_gnutls_x509_privkey_verify_signature (const gnutls_datum_t * tbs,
const gnutls_datum_t * signature,
gnutls_x509_privkey_t issuer)
{
int ret;
ret = verify_sig (tbs, signature, issuer->pk_algorithm,
issuer->params, issuer->params_size);
if (ret < 0)
{
gnutls_assert ();
}
return ret;
}
/**
* gnutls_x509_crt_list_verify - This function verifies the given certificate
list
* @cert_list: is the certificate list to be verified
* @cert_list_length: holds the number of certificate in cert_list
* @CA_list: is the CA list which will be used in verification
* @CA_list_length: holds the number of CA certificate in CA_list
* @CRL_list: holds a list of CRLs.
* @CRL_list_length: the length of CRL list.
* @flags: Flags that may be used to change the verification algorithm. Use OR
of the gnutls_certificate_verify_flags enumerations.
* @verify: will hold the certificate verification output.
*
* This function will try to verify the given certificate list and return its
status.
* Note that expiration and activation dates are not checked
* by this function, you should check them using the appropriate functions.
*
* If no flags are specified (0), this function will use the
* basicConstraints (2.5.29.19) PKIX extension. This means that only a
certificate
* authority is allowed to sign a certificate.
*
* You must also check the peer's name in order to check if the verified
* certificate belongs to the actual peer.
*
* The certificate verification output will be put in @verify and will be
* one or more of the gnutls_certificate_status_t enumerated elements bitwise
or'd.
* For a more detailed verification status use gnutls_x509_crt_verify() per
list
* element.
*
* GNUTLS_CERT_INVALID: the certificate chain is not valid.
*
* GNUTLS_CERT_REVOKED: a certificate in the chain has been revoked.
*
* Returns 0 on success and a negative value in case of an error.
*
**/
int
gnutls_x509_crt_list_verify (const gnutls_x509_crt_t * cert_list,
int cert_list_length,
const gnutls_x509_crt_t * CA_list,
int CA_list_length,
const gnutls_x509_crl_t * CRL_list,
int CRL_list_length, unsigned int flags,
unsigned int *verify)
{
if (cert_list == NULL || cert_list_length == 0)
return GNUTLS_E_NO_CERTIFICATE_FOUND;
/* Verify certificate
*/
*verify =
_gnutls_x509_verify_certificate (cert_list, cert_list_length,
CA_list, CA_list_length, CRL_list,
CRL_list_length, flags);
return 0;
}
/**
* gnutls_x509_crt_verify - This function verifies the given certificate
against a given trusted one
* @cert: is the certificate to be verified
* @CA_list: is one certificate that is considered to be trusted one
* @CA_list_length: holds the number of CA certificate in CA_list
* @flags: Flags that may be used to change the verification algorithm. Use OR
of the gnutls_certificate_verify_flags enumerations.
* @verify: will hold the certificate verification output.
*
* This function will try to verify the given certificate and return its
status.
* The verification output in this functions cannot be GNUTLS_CERT_NOT_VALID.
*
* Returns 0 on success and a negative value in case of an error.
*
**/
int
gnutls_x509_crt_verify (gnutls_x509_crt_t cert,
const gnutls_x509_crt_t * CA_list,
int CA_list_length, unsigned int flags,
unsigned int *verify)
{
int ret;
/* Verify certificate
*/
ret =
_gnutls_verify_certificate2 (cert, CA_list, CA_list_length, flags,
verify);
if (ret < 0)
{
gnutls_assert ();
return ret;
}
return 0;
}
#ifdef ENABLE_PKI
/**
* gnutls_x509_crl_check_issuer - This function checks if the CRL given has
the given issuer
* @crl: is the CRL to be checked
* @issuer: is the certificate of a possible issuer
*
* This function will check if the given CRL was issued by the
* given issuer certificate. It will return true (1) if the given CRL was
issued
* by the given issuer, and false (0) if not.
*
* A negative value is returned in case of an error.
*
**/
int
gnutls_x509_crl_check_issuer (gnutls_x509_crl_t cert,
gnutls_x509_crt_t issuer)
{
return is_crl_issuer (cert, issuer);
}
/**
* gnutls_x509_crl_verify - This function verifies the given crl against a
given trusted one
* @crl: is the crl to be verified
* @CA_list: is a certificate list that is considered to be trusted one
* @CA_list_length: holds the number of CA certificates in CA_list
* @flags: Flags that may be used to change the verification algorithm. Use OR
of the gnutls_certificate_verify_flags enumerations.
* @verify: will hold the crl verification output.
*
* This function will try to verify the given crl and return its status.
* See gnutls_x509_crt_list_verify() for a detailed description of
* return values.
*
* Returns 0 on success and a negative value in case of an error.
*
**/
int
gnutls_x509_crl_verify (gnutls_x509_crl_t crl,
const gnutls_x509_crt_t * CA_list,
int CA_list_length, unsigned int flags,
unsigned int *verify)
{
int ret;
/* Verify crl
*/
ret = _gnutls_verify_crl2 (crl, CA_list, CA_list_length, flags, verify);
if (ret < 0)
{
gnutls_assert ();
return ret;
}
return 0;
}
/* The same as above, but here we've got a CRL.
*/
static int
is_crl_issuer (gnutls_x509_crl_t crl, gnutls_x509_crt_t issuer_cert)
{
gnutls_datum_t dn1 = { NULL, 0 }, dn2 =
{
NULL, 0};
int ret;
ret = _gnutls_x509_crl_get_raw_issuer_dn (crl, &dn1);
if (ret < 0)
{
gnutls_assert ();
goto cleanup;
}
ret = gnutls_x509_crt_get_raw_dn (issuer_cert, &dn2);
if (ret < 0)
{
gnutls_assert ();
return ret;
}
ret = _gnutls_x509_compare_raw_dn (&dn1, &dn2);
cleanup:
_gnutls_free_datum (&dn1);
_gnutls_free_datum (&dn2);
return ret;
}
static inline gnutls_x509_crt_t
find_crl_issuer (gnutls_x509_crl_t crl,
const gnutls_x509_crt_t * trusted_cas, int tcas_size)
{
int i;
/* this is serial search.
*/
for (i = 0; i < tcas_size; i++)
{
if (is_crl_issuer (crl, trusted_cas[i]) == 1)
return trusted_cas[i];
}
gnutls_assert ();
return NULL;
}
/*
* Returns only 0 or 1. If 1 it means that the CRL
* was successfuly verified.
*
* 'flags': an OR of the gnutls_certificate_verify_flags enumeration.
*
* Output will hold information about the verification
* procedure.
*/
static int
_gnutls_verify_crl2 (gnutls_x509_crl_t crl,
const gnutls_x509_crt_t * trusted_cas,
int tcas_size, unsigned int flags, unsigned int *output)
{
/* CRL is ignored for now */
gnutls_datum_t crl_signed_data = { NULL, 0 };
gnutls_datum_t crl_signature = { NULL, 0 };
gnutls_x509_crt_t issuer;
int ret, result;
if (output)
*output = 0;
if (tcas_size >= 1)
issuer = find_crl_issuer (crl, trusted_cas, tcas_size);
else
{
gnutls_assert ();
if (output)
*output |= GNUTLS_CERT_SIGNER_NOT_FOUND | GNUTLS_CERT_INVALID;
return 0;
}
/* issuer is not in trusted certificate
* authorities.
*/
if (issuer == NULL)
{
gnutls_assert ();
if (output)
*output |= GNUTLS_CERT_SIGNER_NOT_FOUND | GNUTLS_CERT_INVALID;
return 0;
}
if (!(flags & GNUTLS_VERIFY_DISABLE_CA_SIGN))
{
if (gnutls_x509_crt_get_ca_status (issuer, NULL) != 1)
{
gnutls_assert ();
if (output)
*output |= GNUTLS_CERT_SIGNER_NOT_CA | GNUTLS_CERT_INVALID;
return 0;
}
}
result =
_gnutls_x509_get_signed_data (crl->crl, "tbsCertList", &crl_signed_data);
if (result < 0)
{
gnutls_assert ();
goto cleanup;
}
result = _gnutls_x509_get_signature (crl->crl, "signature", &crl_signature);
if (result < 0)
{
gnutls_assert ();
goto cleanup;
}
ret =
_gnutls_x509_verify_signature (&crl_signed_data, &crl_signature, issuer);
if (ret < 0)
{
gnutls_assert ();
}
else if (ret == 0)
{
gnutls_assert ();
/* error. ignore it */
if (output)
*output |= GNUTLS_CERT_INVALID;
ret = 0;
}
{
int sigalg;
sigalg = gnutls_x509_crl_get_signature_algorithm (crl);
if (((sigalg == GNUTLS_SIGN_RSA_MD2) &&
!(flags & GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD2)) ||
((sigalg == GNUTLS_SIGN_RSA_MD5) &&
!(flags & GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5)))
{
if (output)
*output |= GNUTLS_CERT_INSECURE_ALGORITHM | GNUTLS_CERT_INVALID;
}
}
result = ret;
cleanup:
_gnutls_free_datum (&crl_signed_data);
_gnutls_free_datum (&crl_signature);
return result;
}
#endif
- gnutls fails to use Verisign CA cert without a Basic Constraint, Douglas E. Engert, 2009/01/07
- Re: gnutls fails to use Verisign CA cert without a Basic Constraint, Simon Josefsson, 2009/01/08
- Re: gnutls fails to use Verisign CA cert without a Basic Constraint,
Douglas E. Engert <=
- Re: gnutls fails to use Verisign CA cert without a Basic Constraint, Simon Josefsson, 2009/01/09
- Re: gnutls fails to use Verisign CA cert without a Basic Constraint, Simon Josefsson, 2009/01/09
- Re: gnutls fails to use Verisign CA cert without a Basic Constraint, Tomas Mraz, 2009/01/09
- Re: gnutls fails to use Verisign CA cert without a Basic Constraint, Simon Josefsson, 2009/01/09
- Re: gnutls fails to use Verisign CA cert without a Basic Constraint, Tomas Mraz, 2009/01/09
- Re: gnutls fails to use Verisign CA cert without a Basic Constraint, Douglas E. Engert, 2009/01/09
- Re: gnutls fails to use Verisign CA cert without a Basic Constraint, Simon Josefsson, 2009/01/09
- Re: gnutls fails to use Verisign CA cert without a Basic Constraint, Daniel Kahn Gillmor, 2009/01/09
- Re: gnutls fails to use Verisign CA cert without a Basic Constraint, Simon Josefsson, 2009/01/10
- Re: gnutls fails to use Verisign CA cert without a Basic Constraint, Douglas E. Engert, 2009/01/09