summaryrefslogtreecommitdiffstatsabout
path: root/src/gnutls_hooks.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gnutls_hooks.c')
-rw-r--r--src/gnutls_hooks.c255
1 files changed, 52 insertions, 203 deletions
diff --git a/src/gnutls_hooks.c b/src/gnutls_hooks.c
index 26917b8..55a1120 100644
--- a/src/gnutls_hooks.c
+++ b/src/gnutls_hooks.c
@@ -36,10 +36,7 @@ static int mpm_is_threaded;
36 36
37static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt); 37static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt);
38/* use side==0 for server and side==1 for client */ 38/* use side==0 for server and side==1 for client */
39static void mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt_t cert, 39static void mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt cert,
40 int side,
41 int export_certificates_enabled);
42static void mgs_add_common_pgpcert_vars(request_rec * r, gnutls_openpgp_crt_t cert,
43 int side, 40 int side,
44 int export_certificates_enabled); 41 int export_certificates_enabled);
45 42
@@ -71,23 +68,9 @@ int ret;
71 mpm_is_threaded = 0; 68 mpm_is_threaded = 0;
72#endif 69#endif
73 70
74 if (gnutls_check_version(LIBGNUTLS_VERSION)==NULL) {
75 fprintf(stderr, "gnutls_check_version() failed. Required: gnutls-%s Found: gnutls-%s\n",
76 LIBGNUTLS_VERSION, gnutls_check_version(NULL));
77 return -3;
78 }
79
80 ret = gnutls_global_init(); 71 ret = gnutls_global_init();
81 if (ret < 0) { 72 if (ret < 0) /* FIXME: can we print here? */
82 fprintf(stderr, "gnutls_global_init: %s\n", gnutls_strerror(ret)); 73 exit(ret);
83 return -3;
84 }
85
86 ret = gnutls_global_init_extra();
87 if (ret < 0) {
88 fprintf(stderr, "gnutls_global_init_extra: %s\n", gnutls_strerror(ret));
89 return -3;
90 }
91 74
92 apr_pool_cleanup_register(pconf, NULL, mgs_cleanup_pre_config, 75 apr_pool_cleanup_register(pconf, NULL, mgs_cleanup_pre_config,
93 apr_pool_cleanup_null); 76 apr_pool_cleanup_null);
@@ -99,18 +82,19 @@ int ret;
99 82
100 gnutls_global_set_log_level(9); 83 gnutls_global_set_log_level(9);
101 gnutls_global_set_log_function(gnutls_debug_log_all); 84 gnutls_global_set_log_function(gnutls_debug_log_all);
102 apr_file_printf(debug_log_fp, "gnutls: %s\n", gnutls_check_version(NULL));
103#endif 85#endif
104 86
105 return OK; 87 return OK;
106} 88}
107 89
90/* We don't support openpgp certificates, yet */
91const static int cert_type_prio[2] = { GNUTLS_CRT_X509, 0 };
92
108static int mgs_select_virtual_server_cb(gnutls_session_t session) 93static int mgs_select_virtual_server_cb(gnutls_session_t session)
109{ 94{
110 mgs_handle_t *ctxt; 95 mgs_handle_t *ctxt;
111 mgs_srvconf_rec *tsc; 96 mgs_srvconf_rec *tsc;
112 int ret; 97 int ret;
113 int cprio[2];
114 98
115 ctxt = gnutls_transport_get_ptr(session); 99 ctxt = gnutls_transport_get_ptr(session);
116 100
@@ -142,22 +126,13 @@ static int mgs_select_virtual_server_cb(gnutls_session_t session)
142 * negotiation. 126 * negotiation.
143 */ 127 */
144 ret = gnutls_priority_set(session, ctxt->sc->priorities); 128 ret = gnutls_priority_set(session, ctxt->sc->priorities);
129 gnutls_certificate_type_set_priority(session, cert_type_prio);
130
131
145 /* actually it shouldn't fail since we have checked at startup */ 132 /* actually it shouldn't fail since we have checked at startup */
146 if (ret < 0) 133 if (ret < 0)
147 return ret; 134 return ret;
148 135
149 /* If both certificate types are not present disallow them from
150 * being negotiated.
151 */
152 if (ctxt->sc->certs_x509[0] != NULL && ctxt->sc->cert_pgp == NULL) {
153 cprio[0] = GNUTLS_CRT_X509;
154 cprio[1] = 0;
155 gnutls_certificate_type_set_priority( session, cprio);
156 } else if (ctxt->sc->cert_pgp != NULL && ctxt->sc->certs_x509[0]==NULL) {
157 cprio[0] = GNUTLS_CRT_OPENPGP;
158 cprio[1] = 0;
159 gnutls_certificate_type_set_priority( session, cprio);
160 }
161 136
162 return 0; 137 return 0;
163} 138}
@@ -168,31 +143,15 @@ static int cert_retrieve_fn(gnutls_session_t session, gnutls_retr_st * ret)
168 143
169 ctxt = gnutls_transport_get_ptr(session); 144 ctxt = gnutls_transport_get_ptr(session);
170 145
171 if (gnutls_certificate_type_get( session) == GNUTLS_CRT_X509) { 146 ret->type = GNUTLS_CRT_X509;
172 ret->type = GNUTLS_CRT_X509; 147 ret->ncerts = ctxt->sc->certs_x509_num;
173 ret->ncerts = ctxt->sc->certs_x509_num; 148 ret->deinit_all = 0;
174 ret->deinit_all = 0;
175
176 ret->cert.x509 = ctxt->sc->certs_x509;
177 ret->key.x509 = ctxt->sc->privkey_x509;
178
179 return 0;
180 } else if (gnutls_certificate_type_get( session) == GNUTLS_CRT_OPENPGP) {
181 ret->type = GNUTLS_CRT_OPENPGP;
182 ret->ncerts = 1;
183 ret->deinit_all = 0;
184
185 ret->cert.pgp = ctxt->sc->cert_pgp;
186 ret->key.pgp = ctxt->sc->privkey_pgp;
187
188 return 0;
189
190 }
191 149
192 return GNUTLS_E_INTERNAL_ERROR; 150 ret->cert.x509 = ctxt->sc->certs_x509;
151 ret->key.x509 = ctxt->sc->privkey_x509;
152 return 0;
193} 153}
194 154
195/* 2048-bit group parameters from SRP specification */
196const char static_dh_params[] = "-----BEGIN DH PARAMETERS-----\n" 155const char static_dh_params[] = "-----BEGIN DH PARAMETERS-----\n"
197 "MIIBBwKCAQCsa9tBMkqam/Fm3l4TiVgvr3K2ZRmH7gf8MZKUPbVgUKNzKcu0oJnt\n" 156 "MIIBBwKCAQCsa9tBMkqam/Fm3l4TiVgvr3K2ZRmH7gf8MZKUPbVgUKNzKcu0oJnt\n"
198 "gZPgdXdnoT3VIxKrSwMxDc1/SKnaBP1Q6Ag5ae23Z7DPYJUXmhY6s2YaBfvV+qro\n" 157 "gZPgdXdnoT3VIxKrSwMxDc1/SKnaBP1Q6Ag5ae23Z7DPYJUXmhY6s2YaBfvV+qro\n"
@@ -208,7 +167,7 @@ const char static_dh_params[] = "-----BEGIN DH PARAMETERS-----\n"
208 * Returns negative on error. 167 * Returns negative on error.
209 */ 168 */
210static int read_crt_cn(server_rec * s, apr_pool_t * p, 169static int read_crt_cn(server_rec * s, apr_pool_t * p,
211 gnutls_x509_crt_t cert, char **cert_cn) 170 gnutls_x509_crt cert, char **cert_cn)
212{ 171{
213 int rv = 0, i; 172 int rv = 0, i;
214 size_t data_len; 173 size_t data_len;
@@ -216,7 +175,6 @@ static int read_crt_cn(server_rec * s, apr_pool_t * p,
216 175
217 *cert_cn = NULL; 176 *cert_cn = NULL;
218 177
219 data_len = 0;
220 rv = gnutls_x509_crt_get_dn_by_oid(cert, 178 rv = gnutls_x509_crt_get_dn_by_oid(cert,
221 GNUTLS_OID_X520_COMMON_NAME, 179 GNUTLS_OID_X520_COMMON_NAME,
222 0, 0, NULL, &data_len); 180 0, 0, NULL, &data_len);
@@ -227,8 +185,8 @@ static int read_crt_cn(server_rec * s, apr_pool_t * p,
227 GNUTLS_OID_X520_COMMON_NAME, 0, 185 GNUTLS_OID_X520_COMMON_NAME, 0,
228 0, *cert_cn, &data_len); 186 0, *cert_cn, &data_len);
229 } else { /* No CN return subject alternative name */ 187 } else { /* No CN return subject alternative name */
230 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, 188 ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
231 "No common name found in certificate for '%s:%d'. Looking for subject alternative name...", 189 "No common name found in certificate for '%s:%d'. Looking for subject alternative name.",
232 s->server_hostname, s->port); 190 s->server_hostname, s->port);
233 rv = 0; 191 rv = 0;
234 /* read subject alternative name */ 192 /* read subject alternative name */
@@ -256,33 +214,9 @@ static int read_crt_cn(server_rec * s, apr_pool_t * p,
256 } 214 }
257 215
258 return rv; 216 return rv;
259}
260
261static int read_pgpcrt_cn(server_rec * s, apr_pool_t * p,
262 gnutls_openpgp_crt_t cert, char **cert_cn)
263{
264 int rv = 0;
265 size_t data_len;
266
267 217
268 *cert_cn = NULL;
269
270 data_len = 0;
271 rv = gnutls_openpgp_crt_get_name(cert, 0, NULL, &data_len);
272
273 if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) {
274 *cert_cn = apr_palloc(p, data_len);
275 rv = gnutls_openpgp_crt_get_name(cert, 0, *cert_cn, &data_len);
276 } else { /* No CN return subject alternative name */
277 ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
278 "No name found in PGP certificate for '%s:%d'.",
279 s->server_hostname, s->port);
280 }
281
282 return rv;
283} 218}
284 219
285
286int 220int
287mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog, 221mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog,
288 apr_pool_t * ptemp, server_rec * base_server) 222 apr_pool_t * ptemp, server_rec * base_server)
@@ -416,9 +350,6 @@ mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog,
416 350
417 if (sc->enabled == GNUTLS_ENABLED_TRUE) { 351 if (sc->enabled == GNUTLS_ENABLED_TRUE) {
418 rv = read_crt_cn(s, p, sc->certs_x509[0], &sc->cert_cn); 352 rv = read_crt_cn(s, p, sc->certs_x509[0], &sc->cert_cn);
419 if (rv < 0 && sc->cert_pgp != NULL) /* try openpgp certificate */
420 rv = read_pgpcrt_cn(s, p, sc->cert_pgp, &sc->cert_cn);
421
422 if (rv < 0) { 353 if (rv < 0) {
423 ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, 354 ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
424 "[GnuTLS] - Cannot find a certificate for host '%s:%d'!", 355 "[GnuTLS] - Cannot find a certificate for host '%s:%d'!",
@@ -547,6 +478,15 @@ mgs_srvconf_rec *mgs_find_sni_server(gnutls_session_t session)
547 478
548 ctxt = gnutls_transport_get_ptr(session); 479 ctxt = gnutls_transport_get_ptr(session);
549 480
481 sni_type = gnutls_certificate_type_get(session);
482 if (sni_type != GNUTLS_CRT_X509) {
483 /* In theory, we could support OpenPGP Certificates. Theory != code. */
484 ap_log_error(APLOG_MARK, APLOG_CRIT, 0,
485 ctxt->c->base_server,
486 "GnuTLS: Only x509 Certificates are currently supported.");
487 return NULL;
488 }
489
550 rv = gnutls_server_name_get(ctxt->session, sni_name, 490 rv = gnutls_server_name_get(ctxt->session, sni_name,
551 &data_len, &sni_type, 0); 491 &data_len, &sni_type, 0);
552 492
@@ -744,11 +684,7 @@ int mgs_hook_fixups(request_rec * r)
744 tmp = mgs_session_id2sz(sbuf, len, buf, sizeof(buf)); 684 tmp = mgs_session_id2sz(sbuf, len, buf, sizeof(buf));
745 apr_table_setn(env, "SSL_SESSION_ID", apr_pstrdup(r->pool, tmp)); 685 apr_table_setn(env, "SSL_SESSION_ID", apr_pstrdup(r->pool, tmp));
746 686
747 if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_X509) 687 mgs_add_common_cert_vars(r, ctxt->sc->certs_x509[0], 0,
748 mgs_add_common_cert_vars(r, ctxt->sc->certs_x509[0], 0,
749 ctxt->sc->export_certificates_enabled);
750 else if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_OPENPGP)
751 mgs_add_common_pgpcert_vars(r, ctxt->sc->cert_pgp, 0,
752 ctxt->sc->export_certificates_enabled); 688 ctxt->sc->export_certificates_enabled);
753 689
754 return rv; 690 return rv;
@@ -810,7 +746,7 @@ int mgs_hook_authz(request_rec * r)
810 */ 746 */
811#define MGS_SIDE ((side==0)?"SSL_SERVER":"SSL_CLIENT") 747#define MGS_SIDE ((side==0)?"SSL_SERVER":"SSL_CLIENT")
812static void 748static void
813mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt_t cert, int side, 749mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt cert, int side,
814 int export_certificates_enabled) 750 int export_certificates_enabled)
815{ 751{
816 unsigned char sbuf[64]; /* buffer to hold serials */ 752 unsigned char sbuf[64]; /* buffer to hold serials */
@@ -916,82 +852,17 @@ mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt_t cert, int side,
916 } 852 }
917 } 853 }
918 } 854 }
919}
920
921static void
922mgs_add_common_pgpcert_vars(request_rec * r, gnutls_openpgp_crt_t cert, int side,
923 int export_certificates_enabled)
924{
925 unsigned char sbuf[64]; /* buffer to hold serials */
926 char buf[AP_IOBUFSIZE];
927 const char *tmp;
928 size_t len;
929 int ret;
930
931 apr_table_t *env = r->subprocess_env;
932
933 if (export_certificates_enabled != 0) {
934 char cert_buf[10 * 1024];
935 len = sizeof(cert_buf);
936
937 if (gnutls_openpgp_crt_export
938 (cert, GNUTLS_OPENPGP_FMT_BASE64, cert_buf, &len) >= 0)
939 apr_table_setn(env,
940 apr_pstrcat(r->pool, MGS_SIDE, "_CERT", NULL),
941 apr_pstrmemdup(r->pool, cert_buf, len));
942
943 }
944
945 len = sizeof(buf);
946 gnutls_openpgp_crt_get_name(cert, 0, buf, &len);
947 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_NAME", NULL),
948 apr_pstrmemdup(r->pool, buf, len));
949 855
950 len = sizeof(sbuf);
951 gnutls_openpgp_crt_get_fingerprint(cert, sbuf, &len);
952 tmp = mgs_session_id2sz(sbuf, len, buf, sizeof(buf));
953 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_FINGERPRINT", NULL),
954 apr_pstrdup(r->pool, tmp));
955
956 ret = gnutls_openpgp_crt_get_version(cert);
957 if (ret > 0)
958 apr_table_setn(env,
959 apr_pstrcat(r->pool, MGS_SIDE, "_M_VERSION", NULL),
960 apr_psprintf(r->pool, "%u", ret));
961
962 apr_table_setn(env,
963 apr_pstrcat(r->pool, MGS_SIDE, "_CERT_TYPE", NULL), "OPENPGP");
964
965 tmp =
966 mgs_time2sz(gnutls_openpgp_crt_get_expiration_time
967 (cert), buf, sizeof(buf));
968 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_END", NULL),
969 apr_pstrdup(r->pool, tmp));
970
971 tmp =
972 mgs_time2sz(gnutls_openpgp_crt_get_creation_time
973 (cert), buf, sizeof(buf));
974 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_START", NULL),
975 apr_pstrdup(r->pool, tmp));
976
977 ret = gnutls_openpgp_crt_get_pk_algorithm(cert, NULL);
978 if (ret >= 0) {
979 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_A_KEY", NULL),
980 gnutls_pk_algorithm_get_name(ret));
981 }
982 856
983} 857}
984 858
985/* TODO: Allow client sending a X.509 certificate chain */ 859
986static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt) 860static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt)
987{ 861{
988 const gnutls_datum_t *cert_list; 862 const gnutls_datum_t *cert_list;
989 unsigned int cert_list_size, status, expired; 863 unsigned int cert_list_size, status, expired;
990 int rv, ret; 864 int rv, ret;
991 union { 865 gnutls_x509_crt_t cert;
992 gnutls_x509_crt_t x509;
993 gnutls_openpgp_crt_t pgp;
994 } cert;
995 apr_time_t activation_time, expiration_time, cur_time; 866 apr_time_t activation_time, expiration_time, cur_time;
996 867
997 cert_list = 868 cert_list =
@@ -1017,56 +888,32 @@ static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt)
1017 return HTTP_FORBIDDEN; 888 return HTTP_FORBIDDEN;
1018 } 889 }
1019 890
1020 if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_X509) { 891 gnutls_x509_crt_init(&cert);
1021 gnutls_x509_crt_init(&cert.x509); 892 rv = gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);
1022 rv = gnutls_x509_crt_import(cert.x509, &cert_list[0], GNUTLS_X509_FMT_DER);
1023 } else if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_OPENPGP) {
1024 gnutls_openpgp_crt_init(&cert.pgp);
1025 rv = gnutls_openpgp_crt_import(cert.pgp, &cert_list[0], GNUTLS_OPENPGP_FMT_RAW);
1026 } else return HTTP_FORBIDDEN;
1027
1028 if (rv < 0) { 893 if (rv < 0) {
1029 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 894 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1030 "GnuTLS: Failed to Verify Peer: " 895 "GnuTLS: Failed to Verify Peer: "
1031 "Failed to import peer certificates."); 896 "Failed to import peer certificates.");
1032 ret = HTTP_FORBIDDEN; 897 ret = HTTP_FORBIDDEN;
1033 goto exit; 898 goto exit;
1034 } 899 }
1035 900
1036 if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_X509) { 901 apr_time_ansi_put(&expiration_time,
1037 apr_time_ansi_put(&expiration_time, 902 gnutls_x509_crt_get_expiration_time(cert));
1038 gnutls_x509_crt_get_expiration_time(cert.x509)); 903 apr_time_ansi_put(&activation_time,
1039 apr_time_ansi_put(&activation_time, 904 gnutls_x509_crt_get_activation_time(cert));
1040 gnutls_x509_crt_get_activation_time(cert.x509));
1041 905
1042 rv = gnutls_x509_crt_verify(cert.x509, ctxt->sc->ca_list, 906 rv = gnutls_x509_crt_verify(cert, ctxt->sc->ca_list,
1043 ctxt->sc->ca_list_size, 0, &status); 907 ctxt->sc->ca_list_size, 0, &status);
1044 } else {
1045 apr_time_ansi_put(&expiration_time,
1046 gnutls_openpgp_crt_get_expiration_time(cert.pgp));
1047 apr_time_ansi_put(&activation_time,
1048 gnutls_openpgp_crt_get_creation_time(cert.pgp));
1049
1050 rv = gnutls_openpgp_crt_verify_ring(cert.pgp, ctxt->sc->pgp_list,
1051 0, &status);
1052 }
1053 908
1054 if (rv < 0) { 909 if (rv < 0) {
1055 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 910 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1056 "GnuTLS: Failed to Verify Peer certificate: (%d) %s", 911 "GnuTLS: Failed to Verify Peer certificate: (%d) %s",
1057 rv, gnutls_strerror(rv)); 912 rv, gnutls_strerror(rv));
1058 if (rv == GNUTLS_E_NO_CERTIFICATE_FOUND)
1059 ap_log_rerror(APLOG_MARK, APLOG_EMERG, 0, r,
1060 "GnuTLS: No certificate was found for verification. Did you set the GnuTLSX509CAFile or GnuTLSPGPKeyringFile directives?");
1061 ret = HTTP_FORBIDDEN; 913 ret = HTTP_FORBIDDEN;
1062 goto exit; 914 goto exit;
1063 } 915 }
1064 916
1065 /* TODO: X509 CRL Verification. */
1066 /* May add later if anyone needs it.
1067 */
1068 /* ret = gnutls_x509_crt_check_revocation(crt, crl_list, crl_list_size); */
1069
1070 expired = 0; 917 expired = 0;
1071 cur_time = apr_time_now(); 918 cur_time = apr_time_now();
1072 if (activation_time > cur_time) { 919 if (activation_time > cur_time) {
@@ -1101,11 +948,16 @@ static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt)
1101 "GnuTLS: Peer Certificate is revoked."); 948 "GnuTLS: Peer Certificate is revoked.");
1102 } 949 }
1103 950
1104 if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_X509) 951 /* TODO: Further Verification. */
1105 mgs_add_common_cert_vars(r, cert.x509, 1, 952 /* Revocation is X.509 non workable paradigm, I really doubt implementation
1106 ctxt->sc->export_certificates_enabled); 953 * is worth doing --nmav
1107 else if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_OPENPGP) 954 */
1108 mgs_add_common_pgpcert_vars(r, cert.pgp, 1, 955/// ret = gnutls_x509_crt_check_revocation(crt, crl_list, crl_list_size);
956
957// mgs_hook_fixups(r);
958// rv = mgs_authz_lua(r);
959
960 mgs_add_common_cert_vars(r, cert, 1,
1109 ctxt->sc->export_certificates_enabled); 961 ctxt->sc->export_certificates_enabled);
1110 962
1111 { 963 {
@@ -1129,10 +981,7 @@ static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt)
1129 } 981 }
1130 982
1131 exit: 983 exit:
1132 if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_X509) 984 gnutls_x509_crt_deinit(cert);
1133 gnutls_x509_crt_deinit(cert.x509);
1134 else if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_OPENPGP)
1135 gnutls_openpgp_crt_deinit(cert.pgp);
1136 return ret; 985 return ret;
1137 986
1138 987