summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2001-07-20 17:50:31 +0000
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2001-07-20 17:50:31 +0000
commitac95734359f80e3c7771f9807e0d57b8e87093e3 (patch)
tree1ff4f329c129b9c1c5c74ed293e82926f1e2a043 /lib
parentb63487a0ae5c0d4cbeeaa6d38f24a6ce6619d7dc (diff)
downloadgnutls-ac95734359f80e3c7771f9807e0d57b8e87093e3.tar.gz
added some kind of certificate checking
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile.am6
-rw-r--r--lib/auth_rsa.c2
-rw-r--r--lib/cert_verify.c34
-rw-r--r--lib/gnutls_cert.c18
-rw-r--r--lib/gnutls_cert.h8
-rw-r--r--lib/gnutls_errors.c1
-rw-r--r--lib/gnutls_errors_int.h1
-rw-r--r--lib/gnutls_hash_int.h8
-rw-r--r--lib/gnutls_int.h4
-rw-r--r--lib/gnutls_pk.c6
-rw-r--r--lib/gnutls_pk.h11
-rw-r--r--lib/gnutls_sig.h3
-rw-r--r--lib/gnutls_sig_check.c209
13 files changed, 284 insertions, 27 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 1849a52e82..bea7d8fee2 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -15,7 +15,8 @@ EXTRA_DIST = debug.h gnutls_compress.h defines.h \
crypt.h libgnutls-config.in libgnutls.m4 gnutls.h.in gnutls_errors_int.h \
cert_asn1.h cert_der.h gnutls_datum.h auth_x509.h gnutls_gcry.h \
ext_dnsname.h gnutls_pk.h gnutls_record.h gnutls_cert.h \
- gnutls_privkey.h gnutls_constate.h gnutls_global.h cert_verify.h
+ gnutls_privkey.h gnutls_constate.h gnutls_global.h cert_verify.h \
+ gnutls_sig.h
lib_LTLIBRARIES = libgnutls.la
libgnutls_la_SOURCES = gnutls_record.c gnutls_compress.c debug.c \
gnutls_cipher.c gnutls_buffers.c gnutls_handshake.c gnutls_num.c \
@@ -27,6 +28,7 @@ libgnutls_la_SOURCES = gnutls_record.c gnutls_compress.c debug.c \
auth_srp.c auth_srp_passwd.c gnutls_v2_compat.c auth_srp_sb64.c \
cert_ASN.y cert_asn1.c cert_der.c gnutls_datum.c auth_rsa.c \
gnutls_gcry.c ext_dnsname.c gnutls_pk.c gnutls_cert.c cert_verify.c\
- gnutls_global.c gnutls_privkey.c gnutls_constate.c gnutls_anon_cred.c
+ gnutls_global.c gnutls_privkey.c gnutls_constate.c gnutls_anon_cred.c \
+ gnutls_sig_check.c
libgnutls_la_LDFLAGS = -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
diff --git a/lib/auth_rsa.c b/lib/auth_rsa.c
index e06467dc23..a05d87cf8e 100644
--- a/lib/auth_rsa.c
+++ b/lib/auth_rsa.c
@@ -311,7 +311,7 @@ int proc_rsa_client_kx(GNUTLS_KEY key, opaque * data, int data_size)
}
ret =
_gnutls_pkcs1_rsa_decrypt(&plaintext, ciphertext, key->u,
- key->A);
+ key->A, 2); /* btype==2 */
if (ret < 0) {
/* in case decryption fails then don't inform
diff --git a/lib/cert_verify.c b/lib/cert_verify.c
index 14d65fd3c4..4f78e502bd 100644
--- a/lib/cert_verify.c
+++ b/lib/cert_verify.c
@@ -25,6 +25,7 @@
#include "cert_der.h"
#include "gnutls_global.h"
#include "gnutls_num.h" /* GMAX */
+#include <gnutls_sig.h>
/* TIME functions */
@@ -169,12 +170,14 @@ int compare_dn(gnutls_cert * cert, gnutls_cert * issuer_cert)
opaque issuer_dn[MAX_DN];
opaque dn[MAX_DN];
+fprintf(stderr, "XXX: %s\nIII: %s\n", cert->issuer_info.common_name, issuer_cert->cert_info.common_name);
/* get the issuer of 'cert'
*/
if (asn1_create_structure(_gnutls_get_pkix(), "PKIX1Implicit88.Certificate", &c2, "certificate2") != ASN_OK) {
gnutls_assert();
return GNUTLS_E_ASN1_ERROR;
}
+
result = asn1_get_der(c2, cert->raw.data, cert->raw.size);
if (result != ASN_OK) {
/* couldn't decode DER */
@@ -182,9 +185,10 @@ int compare_dn(gnutls_cert * cert, gnutls_cert * issuer_cert)
asn1_delete_structure(c2);
return GNUTLS_E_ASN1_PARSING_ERROR;
}
+
issuer_len = sizeof(issuer_dn) - 1;
if ((result =
- asn1_read_value(c2, "certificate2.tbsCertificate.subject.rdnSequence", issuer_dn, &issuer_len)) < 0) {
+ asn1_read_value(c2, "certificate2.tbsCertificate.issuer.rdnSequence", issuer_dn, &issuer_len)) < 0) {
gnutls_assert();
asn1_delete_structure(c2);
return GNUTLS_E_ASN1_PARSING_ERROR;
@@ -198,6 +202,7 @@ int compare_dn(gnutls_cert * cert, gnutls_cert * issuer_cert)
gnutls_assert();
return GNUTLS_E_ASN1_ERROR;
}
+
result = asn1_get_der(c2, issuer_cert->raw.data, issuer_cert->raw.size);
if (result != ASN_OK) {
/* couldn't decode DER */
@@ -205,6 +210,7 @@ int compare_dn(gnutls_cert * cert, gnutls_cert * issuer_cert)
asn1_delete_structure(c2);
return GNUTLS_E_ASN1_PARSING_ERROR;
}
+
len = sizeof(dn) - 1;
if ((result =
asn1_read_value(c2, "certificate2.tbsCertificate.subject.rdnSequence", dn, &len)) < 0) {
@@ -214,10 +220,13 @@ int compare_dn(gnutls_cert * cert, gnutls_cert * issuer_cert)
}
asn1_delete_structure(c2);
+fprintf(stderr, "len: %d\nisslen: %d\n", len,issuer_len);
+
if (memcmp(dn, issuer_dn, GMAX(len, issuer_len)) == 0)
return 0;
- return -1; /* do not match */
+ gnutls_assert();
+ return GNUTLS_E_UNKNOWN_ERROR; /* do not match */
}
@@ -233,6 +242,7 @@ static gnutls_cert *find_issuer(gnutls_cert * cert, gnutls_cert * trusted_cas, i
return &trusted_cas[i];
}
+ gnutls_assert();
return NULL;
}
@@ -245,15 +255,23 @@ int gnutls_verify_certificate2(gnutls_cert * cert, gnutls_cert * trusted_cas, in
gnutls_cert *issuer;
CertificateStatus ret = GNUTLS_CERT_NOT_TRUSTED;
- if (tcas_size > 1)
+ if (tcas_size >= 1)
issuer = find_issuer(cert, trusted_cas, tcas_size);
+ else {
+ gnutls_assert();
+ return ret;
+ }
+
/* issuer is not in trusted certificate
* authorities.
*/
- if (issuer == NULL)
+ if (issuer == NULL) {
+ gnutls_assert();
return GNUTLS_CERT_NOT_TRUSTED;
-
-// ret = verify_signature(cert, issuer);
+ }
+fprintf(stderr, "XXXissuer: %d\n", issuer->subject_pk_algorithm);
+
+ ret = gnutls_verify_signature(cert, issuer);
if (ret != GNUTLS_CERT_TRUSTED)
return ret;
@@ -279,9 +297,9 @@ int gnutls_verify_certificate(gnutls_cert * certificate_list,
if (tcas_size == 0) {
return ret;
}
-
+
for (i = 0; i < clist_size; i++) {
- if (i + 1 > clist_size)
+ if (i + 1 >= clist_size)
break;
if ((ret = gnutls_verify_certificate2(&certificate_list[i], &certificate_list[i + 1], 1, NULL, 0)) != GNUTLS_CERT_TRUSTED) {
diff --git a/lib/gnutls_cert.c b/lib/gnutls_cert.c
index 003e657215..b670332c10 100644
--- a/lib/gnutls_cert.c
+++ b/lib/gnutls_cert.c
@@ -82,7 +82,7 @@ int n,i;
for (i=0;i<n;i++) {
_gnutls_mpi_release( &cert.params[i]);
}
- gnutls_free( cert.params);
+ if (cert.params!=NULL) gnutls_free( cert.params);
gnutls_free_datum( &cert.raw);
@@ -691,10 +691,22 @@ int _gnutls_cert2gnutlsCert(gnutls_cert * gCert, gnutls_datum derCert)
* currently not supported
*/
gnutls_assert();
- asn1_delete_structure(c2);
+ gCert->subject_pk_algorithm = GNUTLS_PK_UNKNOWN;
+ gCert->params = NULL;
+
+ }
- return GNUTLS_E_UNIMPLEMENTED_FEATURE;
+ len = sizeof( gCert->signature);
+ result =
+ asn1_read_value
+ (c2, "certificate2.signature",
+ gCert->signature, &len);
+ if ((len % 8) !=0) {
+ gnutls_assert();
+ asn1_delete_structure(c2);
+ return GNUTLS_E_UNIMPLEMENTED_FEATURE;
}
+ gCert->signature_size = len;
memset( &gCert->cert_info, 0, sizeof(gCert->cert_info));
diff --git a/lib/gnutls_cert.h b/lib/gnutls_cert.h
index 89777e23c9..b76ff71fb2 100644
--- a/lib/gnutls_cert.h
+++ b/lib/gnutls_cert.h
@@ -1,6 +1,8 @@
#ifndef GNUTLS_CERT_H
# define GNUTLS_CERT_H
+#include <gnutls_pk.h>
+
typedef struct {
char common_name[256];
char country[3];
@@ -10,9 +12,6 @@ typedef struct {
char state_or_province_name[256];
} gnutls_DN;
-typedef enum PKAlgorithm { GNUTLS_PK_RSA = 1, GNUTLS_PK_DSA, /* sign only */
- GNUTLS_PK_DH
-} PKAlgorithm;
typedef struct {
MPI *params; /* the size of params depends on the public
@@ -23,6 +22,9 @@ typedef struct {
gnutls_DN cert_info;
gnutls_DN issuer_info;
+ opaque signature[MAX_HASH_SIZE];
+ int signature_size;
+
time_t expiration_time;
time_t activation_time;
diff --git a/lib/gnutls_errors.c b/lib/gnutls_errors.c
index e804936b8e..5a147fe759 100644
--- a/lib/gnutls_errors.c
+++ b/lib/gnutls_errors.c
@@ -60,6 +60,7 @@ static gnutls_error_entry error_algorithms[] = {
GNUTLS_ERROR_ENTRY( GNUTLS_E_ENCRYPTION_FAILED, 1),
GNUTLS_ERROR_ENTRY( GNUTLS_E_PK_DECRYPTION_FAILED, 1),
GNUTLS_ERROR_ENTRY( GNUTLS_E_PK_ENCRYPTION_FAILED, 1),
+ GNUTLS_ERROR_ENTRY( GNUTLS_E_PK_SIGNATURE_FAILED, 1),
GNUTLS_ERROR_ENTRY( GNUTLS_E_DECOMPRESSION_FAILED, 1),
GNUTLS_ERROR_ENTRY( GNUTLS_E_COMPRESSION_FAILED, 1),
GNUTLS_ERROR_ENTRY( GNUTLS_E_MEMORY_ERROR, 1),
diff --git a/lib/gnutls_errors_int.h b/lib/gnutls_errors_int.h
index 3b04dea8fc..e89a2c7194 100644
--- a/lib/gnutls_errors_int.h
+++ b/lib/gnutls_errors_int.h
@@ -43,5 +43,6 @@
#define GNUTLS_E_X509_CERTIFICATE_ERROR -43
#define GNUTLS_E_PK_ENCRYPTION_FAILED -44
#define GNUTLS_E_PK_DECRYPTION_FAILED -45
+#define GNUTLS_E_PK_SIGNATURE_FAILED -46
#define GNUTLS_E_UNIMPLEMENTED_FEATURE -250
diff --git a/lib/gnutls_hash_int.h b/lib/gnutls_hash_int.h
index 3b0dbfa23c..be368331db 100644
--- a/lib/gnutls_hash_int.h
+++ b/lib/gnutls_hash_int.h
@@ -40,7 +40,7 @@ typedef struct {
int keysize;
} GNUTLS_MAC_HANDLE_INT;
typedef GNUTLS_MAC_HANDLE_INT* GNUTLS_MAC_HANDLE;
-
+typedef GNUTLS_MAC_HANDLE GNUTLS_HASH_HANDLE;
#define GNUTLS_HASH_FAILED NULL
#define GNUTLS_MAC_FAILED NULL
@@ -55,10 +55,10 @@ void gnutls_hmac_deinit( GNUTLS_MAC_HANDLE handle, void* digest);
GNUTLS_MAC_HANDLE gnutls_mac_init_ssl3( MACAlgorithm algorithm, void* key, int keylen);
void gnutls_mac_deinit_ssl3( GNUTLS_MAC_HANDLE handle, void* digest);
-GNUTLS_MAC_HANDLE gnutls_hash_init(MACAlgorithm algorithm);
+GNUTLS_HASH_HANDLE gnutls_hash_init(MACAlgorithm algorithm);
int gnutls_hash_get_algo_len(MACAlgorithm algorithm);
-int gnutls_hash(GNUTLS_MAC_HANDLE handle, const void* text, int textlen);
-void gnutls_hash_deinit(GNUTLS_MAC_HANDLE handle, void* digest);
+int gnutls_hash(GNUTLS_HASH_HANDLE handle, const void* text, int textlen);
+void gnutls_hash_deinit(GNUTLS_HASH_HANDLE handle, void* digest);
void *gnutls_ssl3_generate_random(void *secret, int secret_len, void *random, int random_len, int bytes);
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
index 3481a29d24..663e3689cd 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -30,9 +30,9 @@
#define HARD_DEBUG
#define BUFFERS_DEBUG
#define RECORD_DEBUG
-#define HANDSHAKE_DEBUG
+#define HANDSHAKE_DEBUG*/
#define DEBUG
-*/
+
#define SOCKET int
#define LIST ...
diff --git a/lib/gnutls_pk.c b/lib/gnutls_pk.c
index b7bbfc58a4..76b06ce6a0 100644
--- a/lib/gnutls_pk.c
+++ b/lib/gnutls_pk.c
@@ -110,7 +110,7 @@ int _gnutls_pkcs1_rsa_encrypt(gnutls_datum * ciphertext, gnutls_datum plaintext,
*/
int _gnutls_pkcs1_rsa_decrypt(gnutls_datum * plaintext, gnutls_datum ciphertext,
- MPI pkey, MPI n)
+ MPI pkey, MPI n, int btype)
{
int k, esize, i, ret;
MPI c, res;
@@ -153,13 +153,13 @@ int _gnutls_pkcs1_rsa_decrypt(gnutls_datum * plaintext, gnutls_datum ciphertext,
gcry_mpi_release(res);
/* EB = 00||BT||PS||00||D
- * (use block type 2)
+ * (use block type 'btype')
*/
edata[0] = 0;
esize++;
- if (edata[0] != 0 || edata[1] != 2) {
+ if (edata[0] != 0 || edata[1] != btype) {
gnutls_assert();
gnutls_free(edata);
return GNUTLS_E_DECRYPTION_FAILED;
diff --git a/lib/gnutls_pk.h b/lib/gnutls_pk.h
index f6eb0328c7..d6e2d5d673 100644
--- a/lib/gnutls_pk.h
+++ b/lib/gnutls_pk.h
@@ -1,5 +1,14 @@
+#ifndef GNUTLS_PK_H
+# define GNUTLS_PK_H
+
+typedef enum PKAlgorithm { GNUTLS_PK_RSA = 1, GNUTLS_PK_DSA, /* sign only */
+ GNUTLS_PK_DH, GNUTLS_PK_UNKNOWN
+} PKAlgorithm;
+
int _gnutls_pk_encrypt(int algo, MPI * resarr, MPI data, MPI ** pkey);
int _gnutls_pkcs1_rsa_encrypt(gnutls_datum * ciphertext, gnutls_datum plaintext,
MPI pkey, MPI n);
int _gnutls_pkcs1_rsa_decrypt(gnutls_datum * plaintext, gnutls_datum ciphertext,
- MPI pkey, MPI n);
+ MPI pkey, MPI n, int btype);
+
+#endif /* GNUTLS_PK_H */
diff --git a/lib/gnutls_sig.h b/lib/gnutls_sig.h
new file mode 100644
index 0000000000..c8a759884f
--- /dev/null
+++ b/lib/gnutls_sig.h
@@ -0,0 +1,3 @@
+int _gnutls_pkcs1_rsa_verify_sig( gnutls_datum* signature, gnutls_datum *text, MPI m, MPI e);
+CertificateStatus gnutls_verify_signature(gnutls_cert* cert, gnutls_cert* issuer);
+
diff --git a/lib/gnutls_sig_check.c b/lib/gnutls_sig_check.c
new file mode 100644
index 0000000000..c96e17fa6a
--- /dev/null
+++ b/lib/gnutls_sig_check.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2001 Nikos Mavroyanopoulos
+ *
+ * This file is part of GNUTLS.
+ *
+ * GNUTLS is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GNUTLS 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <gnutls_int.h>
+#include <gnutls_errors.h>
+#include <cert_b64.h>
+#include <auth_x509.h>
+#include <gnutls_cert.h>
+#include <cert_asn1.h>
+#include <cert_der.h>
+#include <gnutls_datum.h>
+#include <gnutls_gcry.h>
+#include <gnutls_privkey.h>
+#include <gnutls_global.h>
+#include <gnutls_pk.h>
+
+static gnutls_datum* _gnutls_get_tbs( gnutls_cert* cert) {
+node_asn *c2;
+gnutls_datum * ret;
+opaque str[10*1024];
+int result, len;
+
+ if (asn1_create_structure( _gnutls_get_pkix(), "Certificate", &c2, "certificate")!=ASN_OK) {
+ gnutls_assert();
+ return NULL;
+ }
+
+ result = asn1_get_der( c2, cert->raw.data, cert->raw.size);
+ if (result != ASN_OK) {
+ gnutls_assert();
+ asn1_delete_structure(c2);
+ return NULL;
+ }
+
+ len = sizeof(str)-1;
+ result =
+ asn1_read_value( c2, "certificate.tbsCertificate", str, &len);
+ if (result != ASN_OK) {
+ gnutls_assert();
+ asn1_delete_structure(c2);
+ return NULL;
+ }
+
+ asn1_delete_structure(c2);
+
+ ret = gnutls_malloc(sizeof(gnutls_cert));
+ if (ret==NULL) {
+ gnutls_assert();
+ return NULL;
+ }
+
+ ret->data = gnutls_malloc( len);
+ if (ret->data==NULL) {
+ gnutls_assert();
+ gnutls_free(ret);
+ return NULL;
+ }
+
+ memcpy( ret->data, str, len);
+ ret->size = len;
+
+ return ret;
+}
+
+
+/* we use DER here -- FIXME: use BER
+ */
+static int _gnutls_get_ber_digest_info( const gnutls_datum *info, MACAlgorithm *hash, opaque* digest, int digest_size) {
+node_asn* dinfo;
+int result;
+opaque str[1024];
+int len;
+
+ if (asn1_create_structure( _gnutls_get_pkcs(), "PKCS-1.DigestInfo", &dinfo, "digest_info")!=ASN_OK) {
+ gnutls_assert();
+ return GNUTLS_E_ASN1_ERROR;
+ }
+
+ result = asn1_get_der( dinfo, info->data, info->size);
+ if (result != ASN_OK) {
+ gnutls_assert();
+ asn1_delete_structure(dinfo);
+ return GNUTLS_E_ASN1_PARSING_ERROR;
+ }
+
+ len = sizeof(str)-1;
+ result =
+ asn1_read_value( dinfo, "digest_info.digestAlgorithm.algorithm", str, &len);
+ if (result != ASN_OK) {
+ gnutls_assert();
+ asn1_delete_structure(dinfo);
+ return GNUTLS_E_ASN1_PARSING_ERROR;
+ }
+
+ *hash = -1;
+
+ if ( strcmp(str, "1 2 840 113549 2 5")==0) { /* MD5 */
+ *hash = GNUTLS_MAC_MD5;
+ } else
+ if ( strcmp(str, "xxxxxx")==0) { /* SHA1 ID */
+ *hash = GNUTLS_MAC_SHA;
+ }
+
+ if (*hash==-1) {
+fprintf(stderr, "OID: %s\n", str);
+ gnutls_assert();
+ return GNUTLS_E_UNIMPLEMENTED_FEATURE;
+ }
+
+ len = digest_size;
+ result =
+ asn1_read_value( dinfo, "digest_info.digest", digest, &len);
+ if (result != ASN_OK) {
+ gnutls_assert();
+ asn1_delete_structure(dinfo);
+ return GNUTLS_E_ASN1_PARSING_ERROR;
+ }
+
+ asn1_delete_structure(dinfo);
+
+ return 0;
+}
+
+/* if hash==MD5 then we do RSA-MD5
+ * if hash==SHA then we do RSA-SHA
+ * m is modulus
+ * e is public key
+ */
+int
+_gnutls_pkcs1_rsa_verify_sig( gnutls_datum* signature, gnutls_datum* text, MPI m, MPI e)
+{
+ MACAlgorithm hash;
+ int ret;
+ opaque digest[MAX_HASH_SIZE], md[MAX_HASH_SIZE];
+ int digest_size;
+ GNUTLS_HASH_HANDLE hd;
+ gnutls_datum decrypted;
+
+
+ if ( (ret=_gnutls_pkcs1_rsa_decrypt( &decrypted, *signature, e, m, 1)) < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ /* decrypted is a BER encoded data of type DigestInfo
+ */
+
+ if ( (ret = _gnutls_get_ber_digest_info( &decrypted, &hash, digest, sizeof(digest))) != 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ gnutls_free_datum( &decrypted);
+
+ digest_size = gnutls_hash_get_algo_len(hash);
+
+ hd = gnutls_hash_init(hash);
+ gnutls_hash(hd, text->data, text->size);
+ gnutls_hash_deinit(hd, md);
+
+ if (memcmp( md, digest, digest_size)!=0)
+ return GNUTLS_E_PK_SIGNATURE_FAILED;
+
+ return 0;
+}
+
+CertificateStatus gnutls_verify_signature(gnutls_cert* cert, gnutls_cert* issuer) {
+gnutls_datum signature;
+gnutls_datum* tbs;
+
+ if ( issuer->subject_pk_algorithm == GNUTLS_PK_RSA) {
+ signature.data = cert->signature;
+ signature.size = cert->signature_size;
+
+ tbs = _gnutls_get_tbs( cert);
+ if (tbs==NULL) {
+ gnutls_assert();
+ return GNUTLS_CERT_INVALID;
+ }
+
+ if (_gnutls_pkcs1_rsa_verify_sig( &signature, tbs, issuer->params[1], issuer->params[0])!=0) {
+ gnutls_assert();
+ gnutls_free_datum( tbs);
+ return GNUTLS_CERT_NOT_TRUSTED;
+ }
+ gnutls_free_datum(tbs);
+ return GNUTLS_CERT_TRUSTED;
+ }
+fprintf(stderr, "PK: %d\n", issuer->subject_pk_algorithm);
+ gnutls_assert();
+ return GNUTLS_CERT_INVALID;
+}