Commit d1aacba706d896d109db4c071205ab809985b898

Authored by Perry Werneck
1 parent 68f79a5b

Adjustments in TLS subsystem

src/core/connect.c
... ... @@ -136,6 +136,20 @@
136 136  
137 137 }
138 138  
  139 + void lib3270_notify_tls(H3270 *hSession) {
  140 +
  141 + // Negotiation complete is the connection secure?
  142 + if(hSession->ssl.message->type != LIB3270_NOTIFY_INFO) {
  143 +
  144 + // Ask user what I can do!
  145 + if(lib3270_popup_translated(hSession,(const LIB3270_POPUP *) hSession->ssl.message,1) == ECANCELED) {
  146 + lib3270_disconnect(hSession);
  147 + }
  148 +
  149 + }
  150 +
  151 + }
  152 +
139 153 int lib3270_start_tls(H3270 *hSession)
140 154 {
141 155 hSession->ssl.message = NULL; // Reset message.
... ... @@ -184,27 +198,7 @@
184 198 return rc;
185 199 }
186 200  
187   - // Negotiation complete is the connection secure?
188   - if(hSession->ssl.message->type == LIB3270_NOTIFY_INFO) {
189   -
190   - // Yes! The message was only informational.
191   - set_ssl_state(hSession,LIB3270_SSL_SECURE);
192   -
193   - } else {
194   -
195   - // No! The negotiation completed with a warning or error.
196   - set_ssl_state(hSession,LIB3270_SSL_NEGOTIATED);
197   -
198   - // Ask user what I can do!
199   - debug("********************* [%s]",hSession->ssl.message->name);
200   - debug("********************* [%s]",hSession->ssl.message->label);
201   -
202   - if(lib3270_popup_translated(hSession,(const LIB3270_POPUP *) hSession->ssl.message,1) == ECANCELED) {
203   - return ECANCELED;
204   - }
205   -
206   - }
207   -
  201 + set_ssl_state(hSession,(hSession->ssl.message->type == LIB3270_NOTIFY_INFO ? LIB3270_SSL_SECURE : LIB3270_SSL_NEGOTIATED));
208 202 non_blocking(hSession,True);
209 203  
210 204 return 0;
... ...
src/core/linux/connect.c
... ... @@ -192,6 +192,8 @@
192 192 lib3270_setup_session(hSession);
193 193 lib3270_set_connected_initial(hSession);
194 194  
  195 + lib3270_notify_tls(hSession);
  196 +
195 197 }
196 198  
197 199 int net_reconnect(H3270 *hSession, int seconds)
... ...
src/core/telnet.c
... ... @@ -402,6 +402,7 @@ static int net_connected(H3270 *hSession)
402 402 }
403 403  
404 404 lib3270_setup_session(hSession);
  405 + lib3270_notify_tls(hSession);
405 406  
406 407 return 0;
407 408 }
... ... @@ -1053,7 +1054,12 @@ static void continue_tls(H3270 *hSession, unsigned char *sbbuf, int len)
1053 1054 trace_dsn(hSession,"%s FOLLOWS %s\n", opt(TELOPT_STARTTLS), cmd(SE));
1054 1055  
1055 1056 hSession->ssl.host = 1; // Set host type as SSL.
1056   - lib3270_start_tls(hSession);
  1057 + if(lib3270_start_tls(hSession)) {
  1058 + lib3270_disconnect(hSession);
  1059 + return;
  1060 + }
  1061 +
  1062 + lib3270_notify_tls(hSession);
1057 1063  
1058 1064 }
1059 1065  
... ...
src/include/internals.h
... ... @@ -870,6 +870,9 @@ LIB3270_INTERNAL void set_ssl_state(H3270 *session, LIB3270_SSL_STATE state);
870 870 ///
871 871 LIB3270_INTERNAL int lib3270_start_tls(H3270 *hSession);
872 872  
  873 + LIB3270_INTERNAL void lib3270_notify_tls(H3270 *hSession);
  874 +
  875 +
873 876 /**
874 877 * @brief Emit translated popup message.
875 878 *
... ...
src/include/networking.h
... ... @@ -147,6 +147,16 @@
147 147 /// @brief Get socket options.
148 148 int (*getsockopt)(H3270 *hSession, int level, int optname, void *optval, socklen_t *optlen);
149 149  
  150 + /// @brief Get Peer certificate.
  151 + ///
  152 + /// @return String with the peer certificate (release it with lib3270_free); NULL if not available.
  153 + char * (*getcert)(const H3270 *hSession);
  154 +
  155 + /// @brief Get CRL.
  156 + ///
  157 + /// @return String with the CRL certificate (release it with lib3270_free); NULL if not available.
  158 + char * (*getcrl)(const H3270 *hSession);
  159 +
150 160 } LIB3270_NET_MODULE;
151 161  
152 162 /**
... ...
src/network_modules/openssl/main.c
... ... @@ -203,6 +203,62 @@ static int openssl_network_getsockopt(H3270 *hSession, int level, int optname, v
203 203 return getsockopt(hSession->network.context->sock, level, optname, optval, optlen);
204 204 }
205 205  
  206 +static char * openssl_network_getcert(const H3270 *hSession) {
  207 +
  208 + LIB3270_NET_CONTEXT * context = hSession->network.context;
  209 +
  210 + if(context && context->con) {
  211 + lib3270_autoptr(X509) peer = SSL_get_peer_certificate(context->con);
  212 +
  213 + if(peer) {
  214 +
  215 + lib3270_autoptr(BIO) out = BIO_new(BIO_s_mem());
  216 + unsigned char * data;
  217 + unsigned char * text;
  218 + int n;
  219 +
  220 + X509_print(out,peer);
  221 +
  222 + n = BIO_get_mem_data(out, &data);
  223 + text = (unsigned char *) lib3270_malloc(n+1);
  224 + memcpy(text,data,n);
  225 + text[n] ='\0';
  226 +
  227 + return (char *) text;
  228 + }
  229 + }
  230 +
  231 + errno = ENOTCONN;
  232 + return NULL;
  233 +}
  234 +
  235 +static char * openssl_network_getcrl(const H3270 *hSession) {
  236 +
  237 + LIB3270_NET_CONTEXT * context = hSession->network.context;
  238 +
  239 + if(context->crl.cert) {
  240 +
  241 + lib3270_autoptr(BIO) out = BIO_new(BIO_s_mem());
  242 + unsigned char * data;
  243 + unsigned char * text;
  244 + int n;
  245 +
  246 + X509_print(out,context->crl.cert);
  247 +
  248 + n = BIO_get_mem_data(out, &data);
  249 + text = (unsigned char *) lib3270_malloc(n+1);
  250 + memcpy(text,data,n);
  251 + text[n] ='\0';
  252 +
  253 + return (char *) text;
  254 +
  255 + }
  256 +
  257 + errno = ENOENT;
  258 + return NULL;
  259 +
  260 +}
  261 +
206 262 static int openssl_network_init(H3270 *hSession) {
207 263  
208 264 set_ssl_state(hSession,LIB3270_SSL_UNDEFINED);
... ... @@ -283,7 +339,9 @@ void lib3270_set_libssl_network_module(H3270 *hSession) {
283 339 .is_connected = openssl_network_is_connected,
284 340 .getsockname = openssl_network_getsockname,
285 341 .setsockopt = openssl_network_setsockopt,
286   - .getsockopt = openssl_network_getsockopt
  342 + .getsockopt = openssl_network_getsockopt,
  343 + .getcert = openssl_network_getcert,
  344 + .getcrl = openssl_network_getcrl
287 345 };
288 346  
289 347 debug("%s",__FUNCTION__);
... ...
src/network_modules/openssl/messages.c
... ... @@ -56,7 +56,7 @@ const LIB3270_SSL_MESSAGE * lib3270_openssl_message_from_id(long id) {
56 56 {
57 57 .id = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT,
58 58 .message = {
59   - .type = LIB3270_NOTIFY_ERROR,
  59 + .type = LIB3270_NOTIFY_SECURE,
60 60 .icon = "dialog-error",
61 61 .summary = N_( "Unable to get issuer certificate" ),
62 62 .body = N_( "The issuer certificate of a looked up certificate could not be found. This normally means the list of trusted certificates is not complete." )
... ... @@ -66,8 +66,12 @@ const LIB3270_SSL_MESSAGE * lib3270_openssl_message_from_id(long id) {
66 66 {
67 67 .id = X509_V_ERR_UNABLE_TO_GET_CRL,
68 68 .message = {
  69 +#ifdef SSL_ENABLE_CRL_CHECK
  70 + .type = LIB3270_NOTIFY_SECURE,
  71 +#else
  72 + .type = LIB3270_NOTIFY_INFO,
  73 +#endif // SSL_ENABLE_CRL_CHECK
69 74 .name = "X509UnableToGetCRL",
70   - .type = LIB3270_NOTIFY_ERROR,
71 75 .icon = "security-low",
72 76 .summary = N_( "Unable to get certificate CRL." ),
73 77 .body = N_( "The Certificate revocation list (CRL) of a certificate could not be found." ),
... ... @@ -78,7 +82,7 @@ const LIB3270_SSL_MESSAGE * lib3270_openssl_message_from_id(long id) {
78 82 {
79 83 .id = X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE,
80 84 .message = {
81   - .type = LIB3270_NOTIFY_ERROR,
  85 + .type = LIB3270_NOTIFY_SECURE,
82 86 .icon = "dialog-error",
83 87 .summary = N_( "Unable to decrypt certificate's signature" ),
84 88 .body = N_( "The certificate signature could not be decrypted. This means that the actual signature value could not be determined rather than it not matching the expected value, this is only meaningful for RSA keys." )
... ... @@ -88,7 +92,7 @@ const LIB3270_SSL_MESSAGE * lib3270_openssl_message_from_id(long id) {
88 92 {
89 93 .id = X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE,
90 94 .message = {
91   - .type = LIB3270_NOTIFY_ERROR,
  95 + .type = LIB3270_NOTIFY_SECURE,
92 96 .icon = "dialog-error",
93 97 .summary = N_( "Unable to decrypt CRL's signature" ),
94 98 .body = N_( "The CRL signature could not be decrypted: this means that the actual signature value could not be determined rather than it not matching the expected value. Unused." )
... ... @@ -98,7 +102,7 @@ const LIB3270_SSL_MESSAGE * lib3270_openssl_message_from_id(long id) {
98 102 {
99 103 .id = X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY,
100 104 .message = {
101   - .type = LIB3270_NOTIFY_ERROR,
  105 + .type = LIB3270_NOTIFY_SECURE,
102 106 .icon = "dialog-error",
103 107 .summary = N_( "Unable to decode issuer public key" ),
104 108 .body = N_( "The public key in the certificate SubjectPublicKeyInfo could not be read." )
... ... @@ -108,7 +112,7 @@ const LIB3270_SSL_MESSAGE * lib3270_openssl_message_from_id(long id) {
108 112 {
109 113 .id = X509_V_ERR_CERT_SIGNATURE_FAILURE,
110 114 .message = {
111   - .type = LIB3270_NOTIFY_ERROR,
  115 + .type = LIB3270_NOTIFY_SECURE,
112 116 .icon = "dialog-error",
113 117 .summary = N_( "Certificate signature failure" ),
114 118 .body = N_( "The signature of the certificate is invalid." )
... ... @@ -118,7 +122,7 @@ const LIB3270_SSL_MESSAGE * lib3270_openssl_message_from_id(long id) {
118 122 {
119 123 .id = X509_V_ERR_CRL_SIGNATURE_FAILURE,
120 124 .message = {
121   - .type = LIB3270_NOTIFY_ERROR,
  125 + .type = LIB3270_NOTIFY_SECURE,
122 126 .icon = "dialog-error",
123 127 .summary = N_( "CRL signature failure" ),
124 128 .body = N_( "The signature of the certificate is invalid." )
... ... @@ -129,7 +133,7 @@ const LIB3270_SSL_MESSAGE * lib3270_openssl_message_from_id(long id) {
129 133 .id = X509_V_ERR_CERT_NOT_YET_VALID,
130 134 .message = {
131 135 .type = LIB3270_NOTIFY_WARNING,
132   - .icon = "dialog-warning",
  136 + .icon = "security-medium",
133 137 .summary = N_( "Certificate is not yet valid" ),
134 138 .body = N_( "The certificate is not yet valid: the notBefore date is after the current time." )
135 139 }
... ... @@ -138,8 +142,8 @@ const LIB3270_SSL_MESSAGE * lib3270_openssl_message_from_id(long id) {
138 142 {
139 143 .id = X509_V_ERR_CERT_HAS_EXPIRED,
140 144 .message = {
141   - .type = LIB3270_NOTIFY_ERROR,
142   - .icon = "dialog-error",
  145 + .type = LIB3270_NOTIFY_SECURE,
  146 + .icon = "security-medium",
143 147 .summary = N_( "Certificate has expired" ),
144 148 .body = N_( "The certificate has expired: that is the notAfter date is before the current time." )
145 149 }
... ... @@ -149,7 +153,7 @@ const LIB3270_SSL_MESSAGE * lib3270_openssl_message_from_id(long id) {
149 153 .id = X509_V_ERR_CRL_NOT_YET_VALID,
150 154 .message = {
151 155 .type = LIB3270_NOTIFY_WARNING,
152   - .icon = "dialog-error",
  156 + .icon = "security-medium",
153 157 .summary = N_( "The CRL is not yet valid." ),
154 158 .body = N_( "The Certificate revocation list (CRL) is not yet valid." )
155 159 }
... ... @@ -159,9 +163,9 @@ const LIB3270_SSL_MESSAGE * lib3270_openssl_message_from_id(long id) {
159 163 .id = X509_V_ERR_CRL_HAS_EXPIRED,
160 164 .message = {
161 165 #ifdef SSL_ENABLE_CRL_EXPIRATION_CHECK
162   - .type = LIB3270_NOTIFY_ERROR,
  166 + .type = LIB3270_NOTIFY_SECURE,
163 167 #else
164   - .type = LIB3270_NOTIFY_WARNING,
  168 + .type = LIB3270_NOTIFY_INFO,
165 169 #endif // SSL_ENABLE_CRL_EXPIRATION_CHECK
166 170 .icon = "security-medium",
167 171 .summary = N_( "The CRL has expired." ),
... ... @@ -172,7 +176,7 @@ const LIB3270_SSL_MESSAGE * lib3270_openssl_message_from_id(long id) {
172 176 {
173 177 .id = X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD,
174 178 .message = {
175   - .type = LIB3270_NOTIFY_ERROR,
  179 + .type = LIB3270_NOTIFY_SECURE,
176 180 .icon = "dialog-error",
177 181 .summary = N_( "Format error in certificate's notBefore field" ),
178 182 .body = N_( "The certificate notBefore field contains an invalid time." )
... ... @@ -182,7 +186,7 @@ const LIB3270_SSL_MESSAGE * lib3270_openssl_message_from_id(long id) {
182 186 {
183 187 .id = X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD,
184 188 .message = {
185   - .type = LIB3270_NOTIFY_ERROR,
  189 + .type = LIB3270_NOTIFY_SECURE,
186 190 .icon = "dialog-error",
187 191 .summary = N_( "Format error in certificate's notAfter field" ),
188 192 .body = N_( "The certificate notAfter field contains an invalid time." )
... ... @@ -192,7 +196,7 @@ const LIB3270_SSL_MESSAGE * lib3270_openssl_message_from_id(long id) {
192 196 {
193 197 .id = X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD,
194 198 .message = {
195   - .type = LIB3270_NOTIFY_ERROR,
  199 + .type = LIB3270_NOTIFY_SECURE,
196 200 .icon = "dialog-error",
197 201 .summary = N_( "Format error in CRL's lastUpdate field" ),
198 202 .body = N_( "The CRL lastUpdate field contains an invalid time." )
... ... @@ -202,7 +206,7 @@ const LIB3270_SSL_MESSAGE * lib3270_openssl_message_from_id(long id) {
202 206 {
203 207 .id = X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD,
204 208 .message = {
205   - .type = LIB3270_NOTIFY_ERROR,
  209 + .type = LIB3270_NOTIFY_SECURE,
206 210 .icon = "dialog-error",
207 211 .summary = N_( "Format error in CRL's nextUpdate field" ),
208 212 .body = N_( "The CRL nextUpdate field contains an invalid time." )
... ... @@ -233,11 +237,13 @@ const LIB3270_SSL_MESSAGE * lib3270_openssl_message_from_id(long id) {
233 237 .id = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN,
234 238 .message = {
235 239 #ifdef SSL_ENABLE_SELF_SIGNED_CERT_CHECK
236   - .type = LIB3270_NOTIFY_ERROR,
  240 + .type = LIB3270_NOTIFY_SECURE,
237 241 #else
238   - .type = LIB3270_NOTIFY_WARNING,
  242 + .type = LIB3270_NOTIFY_INFO,
239 243 #endif // SSL_ENABLE_SELF_SIGNED_CERT_CHECK
240   - .icon = "security-medium",
  244 + .name = "SelfSignedCertInChain",
  245 + .icon = "security-low",
  246 + .label = N_("Continue"),
241 247 .summary = N_( "Self signed certificate in certificate chain" ),
242 248 .body = N_( "The certificate chain could be built up using the untrusted certificates but the root could not be found locally." )
243 249 }
... ... @@ -256,7 +262,7 @@ const LIB3270_SSL_MESSAGE * lib3270_openssl_message_from_id(long id) {
256 262 {
257 263 .id = X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE,
258 264 .message = {
259   - .type = LIB3270_NOTIFY_ERROR,
  265 + .type = LIB3270_NOTIFY_SECURE,
260 266 .icon = "security-low",
261 267 .summary = N_( "Unable to verify the first certificate" ),
262 268 .body = N_( "No signatures could be verified because the chain contains only one certificate and it is not self signed." )
... ... @@ -266,7 +272,7 @@ const LIB3270_SSL_MESSAGE * lib3270_openssl_message_from_id(long id) {
266 272 {
267 273 .id = X509_V_ERR_CERT_REVOKED,
268 274 .message = {
269   - .type = LIB3270_NOTIFY_ERROR,
  275 + .type = LIB3270_NOTIFY_SECURE,
270 276 .icon = "security-low",
271 277 .summary = N_( "Certificate revoked" ),
272 278 .body = N_( "The certificate has been revoked." )
... ... @@ -276,7 +282,7 @@ const LIB3270_SSL_MESSAGE * lib3270_openssl_message_from_id(long id) {
276 282 {
277 283 .id = X509_V_ERR_INVALID_CA,
278 284 .message = {
279   - .type = LIB3270_NOTIFY_ERROR,
  285 + .type = LIB3270_NOTIFY_SECURE,
280 286 .icon = "security-low",
281 287 .summary = N_( "Invalid CA certificate" ),
282 288 .body = N_( "A CA certificate is invalid. Either it is not a CA or its extensions are not consistent with the supplied purpose." )
... ... @@ -286,7 +292,7 @@ const LIB3270_SSL_MESSAGE * lib3270_openssl_message_from_id(long id) {
286 292 {
287 293 .id = X509_V_ERR_PATH_LENGTH_EXCEEDED,
288 294 .message = {
289   - .type = LIB3270_NOTIFY_ERROR,
  295 + .type = LIB3270_NOTIFY_SECURE,
290 296 .icon = "dialog-error",
291 297 .summary = N_( "Path length constraint exceeded" ),
292 298 .body = N_( "The basicConstraints pathlength parameter has been exceeded." ),
... ... @@ -296,7 +302,7 @@ const LIB3270_SSL_MESSAGE * lib3270_openssl_message_from_id(long id) {
296 302 {
297 303 .id = X509_V_ERR_INVALID_PURPOSE,
298 304 .message = {
299   - .type = LIB3270_NOTIFY_ERROR,
  305 + .type = LIB3270_NOTIFY_SECURE,
300 306 .icon = "dialog-error",
301 307 .summary = N_( "Unsupported certificate purpose" ),
302 308 .body = N_( "The supplied certificate cannot be used for the specified purpose." )
... ... @@ -316,7 +322,7 @@ const LIB3270_SSL_MESSAGE * lib3270_openssl_message_from_id(long id) {
316 322 {
317 323 .id = X509_V_ERR_CERT_REJECTED,
318 324 .message = {
319   - .type = LIB3270_NOTIFY_ERROR,
  325 + .type = LIB3270_NOTIFY_SECURE,
320 326 .icon = "security-low",
321 327 .summary = N_( "Certificate rejected" ),
322 328 .body = N_( "The root CA is marked to reject the specified purpose." )
... ... @@ -326,7 +332,7 @@ const LIB3270_SSL_MESSAGE * lib3270_openssl_message_from_id(long id) {
326 332 {
327 333 .id = X509_V_ERR_SUBJECT_ISSUER_MISMATCH,
328 334 .message = {
329   - .type = LIB3270_NOTIFY_ERROR,
  335 + .type = LIB3270_NOTIFY_SECURE,
330 336 .icon = "security-low",
331 337 .summary = N_( "Subject issuer mismatch" ),
332 338 .body = N_( "The current candidate issuer certificate was rejected because its subject name did not match the issuer name of the current certificate. Only displayed when the -issuer_checks option is set." )
... ... @@ -336,7 +342,7 @@ const LIB3270_SSL_MESSAGE * lib3270_openssl_message_from_id(long id) {
336 342 {
337 343 .id = X509_V_ERR_AKID_SKID_MISMATCH,
338 344 .message = {
339   - .type = LIB3270_NOTIFY_ERROR,
  345 + .type = LIB3270_NOTIFY_SECURE,
340 346 .icon = "dialog-error",
341 347 .summary = N_( "Authority and subject key identifier mismatch" ),
342 348 .body = N_( "The current candidate issuer certificate was rejected because its subject key identifier was present and did not match the authority key identifier current certificate. Only displayed when the -issuer_checks option is set." )
... ... @@ -346,7 +352,7 @@ const LIB3270_SSL_MESSAGE * lib3270_openssl_message_from_id(long id) {
346 352 {
347 353 .id = X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH,
348 354 .message = {
349   - .type = LIB3270_NOTIFY_ERROR,
  355 + .type = LIB3270_NOTIFY_SECURE,
350 356 .icon = "dialog-error",
351 357 .summary = N_( "Authority and issuer serial number mismatch" ),
352 358 .body = N_( "The current candidate issuer certificate was rejected because its issuer name and serial number was present and did not match the authority key identifier of the current certificate. Only displayed when the -issuer_checks option is set." )
... ... @@ -356,7 +362,7 @@ const LIB3270_SSL_MESSAGE * lib3270_openssl_message_from_id(long id) {
356 362 {
357 363 .id = X509_V_ERR_KEYUSAGE_NO_CERTSIGN,
358 364 .message = {
359   - .type = LIB3270_NOTIFY_ERROR,
  365 + .type = LIB3270_NOTIFY_SECURE,
360 366 .icon = "dialog-error",
361 367 .summary = N_( "Key usage does not include certificate signing" ),
362 368 .body = N_( "The current candidate issuer certificate was rejected because its keyUsage extension does not permit certificate signing." )
... ...
src/network_modules/state.c
... ... @@ -31,12 +31,12 @@
31 31 #include <internals.h>
32 32 #include <errno.h>
33 33 #include <lib3270.h>
34   -#include <lib3270/internals.h>
35 34 #include <lib3270/popup.h>
36 35 #include <lib3270/trace.h>
37 36 #include <trace_dsc.h>
38 37 #include <lib3270/log.h>
39 38 #include <lib3270/trace.h>
  39 +#include <networking.h>
40 40  
41 41 #ifdef HAVE_LIBSSL
42 42 #include <openssl/ssl.h>
... ... @@ -114,18 +114,18 @@ LIB3270_EXPORT const char * lib3270_get_ssl_state_description(const H3270 *hSess
114 114  
115 115 LIB3270_EXPORT char * lib3270_get_ssl_crl_text(const H3270 *hSession) {
116 116  
117   -#ifndef DEBUG
118   - #error Implementar!
119   -#endif // DEBUG
  117 + if(hSession->network.module && hSession->network.module->getcrl)
  118 + return hSession->network.module->getcrl(hSession);
120 119  
  120 + errno = ENOTSUP;
121 121 return NULL;
122 122 }
123 123  
124 124 LIB3270_EXPORT char * lib3270_get_ssl_peer_certificate_text(const H3270 *hSession) {
125 125  
126   -#ifndef DEBUG
127   - #error Implementar!
128   -#endif // DEBUG
  126 + if(hSession->network.module && hSession->network.module->getcert)
  127 + return hSession->network.module->getcert(hSession);
129 128  
  129 + errno = ENOTSUP;
130 130 return NULL;
131 131 }
... ...