gnutls-devel
[Top][All Lists]
Advanced

[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

reply via email to

[Prev in Thread] Current Thread [Next in Thread]