]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Added bogus TLS record version check in the gnutls-cli-debug tool.
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Wed, 26 Mar 2003 12:43:22 +0000 (12:43 +0000)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Wed, 26 Mar 2003 12:43:22 +0000 (12:43 +0000)
15 files changed:
configure.in
lib/gnutls_handshake.c
lib/gnutls_int.h
lib/gnutls_record.c
lib/gnutls_state.c
lib/gnutls_state.h
lib/minitasn1/coding.c
lib/minitasn1/element.c
lib/minitasn1/int.h
lib/minitasn1/libtasn1.h
lib/minitasn1/parser_aux.c
lib/pkix.asn
src/tests.c
src/tests.h
src/tls_test.c

index 57f58694b28c1fecd54f922c0bf6ec5573063819..e47c72b610212680002ff79682b5995bd150301b 100644 (file)
@@ -12,7 +12,7 @@ AC_DEFINE_UNQUOTED(T_OS, "$target_os", [OS name])
 dnl Gnutls Version
 GNUTLS_MAJOR_VERSION=0
 GNUTLS_MINOR_VERSION=9
-GNUTLS_MICRO_VERSION=3
+GNUTLS_MICRO_VERSION=4
 GNUTLS_VERSION=$GNUTLS_MAJOR_VERSION.$GNUTLS_MINOR_VERSION.$GNUTLS_MICRO_VERSION
 
 AC_DEFINE_UNQUOTED(GNUTLS_VERSION, "$GNUTLS_VERSION", [version of gnutls])
index 0f8a95497d08adf3ae08cd4e111abb2f53a0b28a..863d961805239f80b52d681bbeffbbdd7b679917 100644 (file)
@@ -575,8 +575,7 @@ int _gnutls_server_select_suite(gnutls_session session, opaque *data, int datale
                for (i = 0; i < x; i++) {
                        if (memcmp(ciphers[i].CipherSuite, &data[j], 2) ==
                            0) {
-                               _gnutls_handshake_log("HSK: Selected cipher suite: ");
-                               _gnutls_handshake_log("%s\n",
+                               _gnutls_handshake_log("HSK: Selected cipher suite: %s\n",
                                            _gnutls_cipher_suite_get_name(*
                                                                          ((GNUTLS_CipherSuite *) & data[j])));
                                memcpy(session->security_parameters.current_cipher_suite.CipherSuite, ciphers[i].CipherSuite, 2);
@@ -1482,18 +1481,15 @@ static int _gnutls_send_client_hello(gnutls_session session, int again)
                 */
                _gnutls_set_adv_version( session, hver);
 
-               /* Some implementations do not interoperate if we send a
+               /* Some old implementations do not interoperate if we send a
                 * different version in the record layer.
                 * It seems they prefer to read the record's version
                 * as the one we actually requested.
-                *  The proper behaviour is to use the one in the client hello 
+                * The proper behaviour is to use the one in the client hello 
                 * handshake packet and ignore the one in the packet's record 
                 * header.
                 */
-               if (session->internals.default_record_version==0)
-                       _gnutls_set_current_version(session, hver);
-               else _gnutls_set_current_version(session,
-                       session->internals.default_record_version);
+               _gnutls_set_current_version(session, hver);
 
                /* In order to know when this session was initiated.
                 */
index 21e15ec431aacd5b65686c6efd5ab7a193e5fafe..94b83f0f7929dbb3912c9b2f2d8468e7d2b8ae64 100644 (file)
@@ -1,7 +1,7 @@
 /*
- *      Copyright (C) 2000,2001,2002,2003 Nikos Mavroyanopoulos
+ *  Copyright (C) 2000,2001,2002,2003 Nikos Mavroyanopoulos
  *
- * This file is part of GNUTLS.
+ *  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   
@@ -578,7 +578,7 @@ typedef struct {
 
        /* This holds the default version that our first
         * record packet will have. */
-       gnutls_protocol_version         default_record_version;
+       opaque                  default_record_version[2];
 
        int                     cbc_protection_hack;
 
index 92fd6e4801867382bca04c0f94f6e38dae4c3cfb..0625b95d45115dfd2e96468fb7d86df0360e05ce 100644 (file)
@@ -105,7 +105,8 @@ void gnutls_transport_set_ptr(gnutls_session session, gnutls_transport_ptr ptr)
   *
   **/
 void gnutls_transport_set_ptr2(gnutls_session session, gnutls_transport_ptr recv_ptr,
-       gnutls_transport_ptr send_ptr) {
+       gnutls_transport_ptr send_ptr) 
+{
        session->internals.transport_send_ptr = send_ptr;
        session->internals.transport_recv_ptr = recv_ptr;
 }
@@ -118,7 +119,8 @@ void gnutls_transport_set_ptr2(gnutls_session session, gnutls_transport_ptr recv
   * PULL). This must have been set using gnutls_transport_set_ptr().
   *
   **/
-gnutls_transport_ptr gnutls_transport_get_ptr(gnutls_session session) {
+gnutls_transport_ptr gnutls_transport_get_ptr(gnutls_session session) 
+{
        return session->internals.transport_recv_ptr;
 }
 
@@ -222,6 +224,25 @@ static int _gnutls_session_is_valid( gnutls_session session) {
        return 0;
 }
 
+/* Copies the record version into the headers. The 
+ * version, must have 2 bytes at least.
+ */
+inline static void copy_record_version( gnutls_session session, HandshakeType htype, 
+       opaque version[2])
+{
+gnutls_protocol_version lver;
+
+       if (htype != GNUTLS_CLIENT_HELLO || session->internals.default_record_version[0] == 0) {
+               lver = gnutls_protocol_get_version( session);
+
+               version[0] = _gnutls_version_get_major( lver);
+               version[1] = _gnutls_version_get_minor( lver);
+       } else {
+               version[0] = session->internals.default_record_version[0];
+               version[1] = session->internals.default_record_version[1];
+       }
+}
+
 static
 ssize_t _gnutls_create_empty_record( gnutls_session session, ContentType type,
        opaque* erecord, unsigned int erecord_size)
@@ -230,7 +251,6 @@ ssize_t _gnutls_create_empty_record( gnutls_session session, ContentType type,
        int retval;
        int data2send;
        uint8 headers[5];
-       gnutls_protocol_version lver;
 
        if (type!=GNUTLS_APPLICATION_DATA ||
                _gnutls_cipher_is_block( gnutls_cipher_get(session))!=CIPHER_BLOCK) 
@@ -239,16 +259,9 @@ ssize_t _gnutls_create_empty_record( gnutls_session session, ContentType type,
                 */
                return 0;
 
-       headers[0]=type;
+       headers[0] = type;
        
-       lver = gnutls_protocol_get_version(session);
-       if (lver==GNUTLS_VERSION_UNKNOWN) {
-               gnutls_assert();
-               return GNUTLS_E_INTERNAL_ERROR;
-       }
-
-       headers[1]=_gnutls_version_get_major( lver);
-       headers[2]=_gnutls_version_get_minor( lver);
+       copy_record_version( session, (HandshakeType)(-1), &headers[1]);
 
        data2send = 0;
 
@@ -294,7 +307,6 @@ ssize_t _gnutls_send_int( gnutls_session session, ContentType type, HandshakeTyp
        int data2send_size;
        uint8 headers[5];
        const uint8 *data=_data;
-       gnutls_protocol_version lver;
        int erecord_size = 0;
        opaque* erecord = NULL;
 
@@ -316,16 +328,13 @@ ssize_t _gnutls_send_int( gnutls_session session, ContentType type, HandshakeTyp
 
 
 
-       headers[0]=type;
+       headers[0] = type;
        
-       lver = gnutls_protocol_get_version(session);
-       if (lver==GNUTLS_VERSION_UNKNOWN) {
-               gnutls_assert();
-               return GNUTLS_E_INTERNAL_ERROR;
-       }
+       /* Use the default record version, if it is
+        * set.
+        */
+       copy_record_version( session, htype, &headers[1]);
 
-       headers[1]=_gnutls_version_get_major( lver);
-       headers[2]=_gnutls_version_get_minor( lver);
 
        _gnutls_record_log( "REC[%x]: Sending Packet[%d] %s(%d) with length: %d\n",
                session, (int) _gnutls_uint64touint32(&session->connection_state.write_sequence_number), _gnutls_packet2str(type), type, sizeofdata);
@@ -498,7 +507,7 @@ static int _gnutls_check_buffers( gnutls_session session, ContentType type, opaq
  * content type.
  */
 static int _gnutls_check_record_headers( gnutls_session session, uint8 headers[RECORD_HEADER_SIZE], ContentType type, 
-       HandshakeType htype, /*output*/ ContentType *recv_type, gnutls_protocol_version *version, uint16 *length, uint16* header_size) {
+       HandshakeType htype, /*output*/ ContentType *recv_type, opaque version[2], uint16 *length, uint16* header_size) {
 
        /* Read the first two bytes to determine if this is a 
         * version 2 message 
@@ -509,7 +518,9 @@ static int _gnutls_check_record_headers( gnutls_session session, uint8 headers[R
                /* if msb set and expecting handshake message
                 * it should be SSL 2 hello 
                 */
-               *version = GNUTLS_VERSION_UNKNOWN; /* assume unknown version */
+               version[0] = 3; /* assume SSL 3.0 */
+               version[1] = 0;
+
                *length = (((headers[0] & 0x7f) << 8)) | headers[1];
 
                /* SSL 2.0 headers */
@@ -528,9 +539,8 @@ static int _gnutls_check_record_headers( gnutls_session session, uint8 headers[R
                /* version 3.x 
                 */
                *recv_type = headers[0];
-#ifdef CHECK_RECORD_VERSION
-               *version = _gnutls_version_get( headers[1], headers[2]);
-#endif
+               version[0] = headers[1];
+               version[1] = headers[2];
 
                /* No DECR_LEN, since headers has enough size. 
                 */
@@ -544,14 +554,15 @@ static int _gnutls_check_record_headers( gnutls_session session, uint8 headers[R
  * negotiated in the handshake.
  */
 inline
-static int _gnutls_check_record_version( gnutls_session session, HandshakeType htype, gnutls_protocol_version version
+static int _gnutls_check_record_version( gnutls_session session, HandshakeType htype, opaque version[2]
 {
 #ifdef CHECK_RECORD_VERSION
-       if ( (htype!=GNUTLS_CLIENT_HELLO && htype!=GNUTLS_SERVER_HELLO) && gnutls_protocol_get_version(session) != version) {
-               gnutls_assert();
+       if ( (htype!=GNUTLS_CLIENT_HELLO && htype!=GNUTLS_SERVER_HELLO) && 
+               gnutls_protocol_get_version(session) != _gnutls_version_get( version[0], version[1])) {
 
+               gnutls_assert();
                _gnutls_record_log( "REC[%x]: INVALID VERSION PACKET: (%d) %d.%d\n", 
-                       session, htype, _gnutls_version_get_major(version), _gnutls_version_get_minor(version));
+                       session, htype, version[0], version[1]);
 
                return GNUTLS_E_UNSUPPORTED_VERSION_PACKET;
        }
@@ -674,7 +685,7 @@ ssize_t _gnutls_recv_int( gnutls_session session, ContentType type, HandshakeTyp
 {
        uint8 *tmpdata;
        int tmplen;
-       gnutls_protocol_version version;
+       opaque version[2];
        uint8 *headers;
        ContentType recv_type;
        uint16 length;
@@ -726,7 +737,7 @@ ssize_t _gnutls_recv_int( gnutls_session session, ContentType type, HandshakeTyp
                return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
        }
 
-       if ( (ret=_gnutls_check_record_headers( session, headers, type, htype, &recv_type, &version, &length, &header_size)) < 0) {
+       if ( (ret=_gnutls_check_record_headers( session, headers, type, htype, &recv_type, version, &length, &header_size)) < 0) {
                gnutls_assert();
                return ret;
        }
index 624bdde8a025a6ec98e7adcce9345532c9d9fed5..a8120e43267c5f183b24fa0b53717be6b634ac54 100644 (file)
@@ -481,16 +481,19 @@ int _gnutls_openpgp_send_fingerprint(gnutls_session session) {
 /*-
   * _gnutls_record_set_default_version - Used to set the default version for the first record packet
   * @session: is a &gnutls_session structure.
-  * @version: is a tls version
+  * @major: is a tls major version
+  * @minor: is a tls minor version
   *
   * This function sets the default version that we will use in the first
   * record packet (client hello). This function is only useful to people
   * that know TLS internals and want to debug other implementations.
   *
   -*/
-void _gnutls_record_set_default_version(gnutls_session session, gnutls_protocol_version version)
+void _gnutls_record_set_default_version(gnutls_session session,
+       unsigned char major, unsigned char minor)
 {
-       session->internals.default_record_version = version;
+       session->internals.default_record_version[0] = major;
+       session->internals.default_record_version[1] = minor;
 }
 
 /**
index ae34e02bec400fbde444ed0df9a2c0c0036006c7..caf3b1f1b5e28af9ad4271a204d8ae1e7a5fb8ad 100644 (file)
@@ -3,8 +3,6 @@
 
 #include <gnutls_int.h>
 
-void _gnutls_record_set_default_version(gnutls_session session, gnutls_protocol_version version);
-
 void _gnutls_session_cert_type_set( gnutls_session session, gnutls_certificate_type);
 gnutls_kx_algorithm gnutls_kx_get( gnutls_session session);
 gnutls_cipher_algorithm        gnutls_cipher_get( gnutls_session session);
index 8add4692cc9179b884f833a990ecbe0098409d2d..ed38411a0b407d8d26f2e5560bf1d1ac1c3b039f 100644 (file)
@@ -807,15 +807,21 @@ asn1_der_coding(ASN1_TYPE element,const char *name,unsigned char *der,int *len,
       move=RIGHT;
       break;
     case TYPE_OBJECT_ID:
-      if(p->value==NULL){
+      if((p->type&CONST_DEFAULT) && (p->value==NULL)){
+       counter=counter_old;
+       max_len=max_len_old;
+      }
+      else{
+       if(p->value==NULL){
          _asn1_error_description_value_not_found(p,ErrorDescription);
          return ASN1_VALUE_NOT_FOUND;
+       }
+       len2=max_len;
+       ris=_asn1_objectid_der(p->value,der+counter,&len2);
+       if(ris==ASN1_MEM_ALLOC_ERROR) return ris;
+       max_len-=len2;
+       counter+=len2;
       }
-      len2=max_len;
-      ris=_asn1_objectid_der(p->value,der+counter,&len2);
-      if(ris==ASN1_MEM_ALLOC_ERROR) return ris;
-      max_len-=len2;
-      counter+=len2;
       move=RIGHT;
       break;
     case TYPE_TIME:
index ff1ac0f122ffa18a3b755212f08f964ad88ed416..207ff67b4a986603f53fd1554aa5e39835f0fc22 100644 (file)
@@ -389,6 +389,14 @@ asn1_write_value(node_asn *node_root,const char *name,
     for(k=0;k<strlen(value);k++)
       if((!isdigit(value[k])) && (value[k]!='.') && (value[k]!='+')) 
        return ASN1_VALUE_NOT_VALID; 
+    if(node->type&CONST_DEFAULT){
+      p=node->down;
+      while(type_field(p->type)!=TYPE_DEFAULT) p=p->right;
+      if(!strcmp(value,p->value)){
+       _asn1_set_value(node,NULL,0);
+       break;
+      } 
+    }
     _asn1_set_value(node,value,strlen(value)+1);
     break;
   case TYPE_TIME:
@@ -665,7 +673,13 @@ asn1_read_value(node_asn *root,const char *name,unsigned char *value, int *len)
        p=p->right;
       }
       *len = strlen(value) + 1;
-    } else {
+    } 
+    else if((node->type&CONST_DEFAULT) && (node->value==NULL)){
+      p=node->down;
+      while(type_field(p->type)!=TYPE_DEFAULT) p=p->right;
+      PUT_STR_VALUE(value, value_size, p->value);
+      }
+    else {
       PUT_STR_VALUE(value, value_size, node->value);
     }
     break;
index cd2220414f01567749cdbe920d90bc3730fec06e..0daed1d397beb4832236bc3afc0024ed473fc2da 100644 (file)
@@ -32,7 +32,7 @@
 
 #include <mem.h>
 
-#define LIBTASN1_VERSION "0.2.3"
+#define LIBTASN1_VERSION "0.2.4"
 
 #define MAX32 4294967295
 #define MAX24 16777215
index bcbb84f440a15142fb6b192cd2a9eacdeb440bbc..89f73e14f7e90464159a0f6876f5fa14bb7a59c6 100644 (file)
@@ -28,7 +28,7 @@
 extern "C" {
 #endif
 
-#define LIBTASN1_VERSION "0.2.3"
+#define LIBTASN1_VERSION "0.2.4"
 
 #include <sys/types.h>
 #include <time.h>
index 2444f3d9a411961d70811065178736508634f692..6f33563fae61ded8b27adbbc0204d829ec7cbfd5 100644 (file)
@@ -518,7 +518,7 @@ asn1_retCode
 _asn1_expand_object_id(ASN1_TYPE node)
 {
   node_asn *p,*p2,*p3,*p4,*p5;
-  char name_root[129],name2[129];
+  char name_root[MAX_NAME_SIZE],name2[2*MAX_NAME_SIZE+1];
   int move;
  
   if(node==NULL) return ASN1_ELEMENT_NOT_FOUND;
@@ -584,6 +584,55 @@ _asn1_expand_object_id(ASN1_TYPE node)
     if(move==UP) p=_asn1_find_up(p);
   }
 
+
+  /*******************************/
+  /*       expand DEFAULT        */
+  /*******************************/
+  p=node;
+  move=DOWN;
+
+  while(!((p==node) && (move==UP))){
+    if(move!=UP){
+      if((type_field(p->type)==TYPE_OBJECT_ID) && 
+        (p->type&CONST_DEFAULT)){
+       p2=p->down;
+        if(p2 && (type_field(p2->type)==TYPE_DEFAULT)){
+         _asn1_str_cpy(name2, sizeof(name2), name_root);
+         _asn1_str_cat(name2, sizeof(name2), ".");
+         _asn1_str_cat(name2, sizeof(name2), p2->value);
+         p3=_asn1_find_node(node,name2);
+         if(!p3 || (type_field(p3->type)!=TYPE_OBJECT_ID) ||
+            !(p3->type&CONST_ASSIGN)) return ASN1_ELEMENT_NOT_FOUND;
+         p4=p3->down;
+         name2[0]=0;
+         while(p4){
+           if(type_field(p4->type)==TYPE_CONSTANT){
+             if(name2[0]) _asn1_str_cat(name2,sizeof(name2),".");
+             _asn1_str_cat(name2,sizeof(name2),p4->value);
+           }
+           p4=p4->right;
+         }
+         _asn1_set_value(p2,name2,strlen(name2)+1);
+       }
+      }
+      move=DOWN;
+    }
+    else move=RIGHT;
+
+    if(move==DOWN){
+      if(p->down) p=p->down;
+      else move=RIGHT;
+    }
+    
+    if(p==node) {move=UP; continue;}
+
+    if(move==RIGHT){
+      if(p->right) p=p->right;
+      else move=UP;
+    }
+    if(move==UP) p=_asn1_find_up(p);
+  }
+
   return ASN1_SUCCESS;
 }
 
@@ -674,6 +723,22 @@ _asn1_check_identifier(ASN1_TYPE node)
        return ASN1_IDENTIFIER_NOT_FOUND;
       } 
     }
+    else if((type_field(p->type)==TYPE_OBJECT_ID) && 
+           (p->type&CONST_DEFAULT)){
+      p2=p->down;
+      if(p2 && (type_field(p2->type)==TYPE_DEFAULT)){
+       _asn1_str_cpy(name2, sizeof(name2), node->name);
+       _asn1_str_cat(name2, sizeof(name2), ".");
+       _asn1_str_cat(name2, sizeof(name2), p2->value);
+       strcpy(_asn1_identifierMissing,p2->value);
+       p2=_asn1_find_node(node,name2);
+       if(!p2 || (type_field(p2->type)!=TYPE_OBJECT_ID) ||
+          !(p2->type&CONST_ASSIGN))
+         return ASN1_IDENTIFIER_NOT_FOUND;
+       else
+         _asn1_identifierMissing[0]=0;
+      }
+    }
     else if((type_field(p->type)==TYPE_OBJECT_ID) && 
            (p->type&CONST_ASSIGN)){
       p2=p->down;
index a175d1c794525a0eec58addae38c098bdda0ffa8..f278026ce78ca928d098e20a9cadb058c99a430d 100644 (file)
@@ -1070,7 +1070,7 @@ pkcs-5-PBKDF2-params ::= SEQUENCE {
   },
   iterationCount INTEGER (1..MAX),
   keyLength INTEGER (1..MAX) OPTIONAL,
-  prf AlgorithmIdentifier OPTIONAL -- DEFAULT pkcs-5-algid-hmacWithSHA1 
+  prf AlgorithmIdentifier OPTIONAL -- DEFAULT pkcs-5-id-hmacWithSHA1 
 }
 
 END
index ae3ba1f54e8a2f812476a57b41a5bde9a3ab7ac9..153b8c7282a150d48987a8e178d87a5239d5994f 100644 (file)
@@ -489,7 +489,8 @@ int ret;
        return ret;
 }
 
-void _gnutls_record_set_default_version(gnutls_session session, gnutls_protocol_version version);
+void _gnutls_record_set_default_version(gnutls_session session, unsigned char major,
+       unsigned char minor);
 
 int test_version_rollback( gnutls_session session) {
 int ret;
@@ -509,7 +510,7 @@ int ret;
        ADD_ALL_MACS(session);
        ADD_ALL_KX(session);
        gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred);
-       _gnutls_record_set_default_version( session, GNUTLS_SSL3);
+       _gnutls_record_set_default_version( session, 3, 0);
 
        ret = do_handshake( session);
        if (ret!=SUCCEED) return ret;
@@ -520,6 +521,28 @@ int ret;
        return SUCCEED;
 }
 
+/* See if the server tolerates out of bounds
+ * record layer versions in the first client hello
+ * message.
+ */
+int test_version_oob( gnutls_session session) {
+int ret;
+       /* here we enable both SSL 3.0 and TLS 1.0
+        * and we connect using a 5.5 record version.
+        */
+       ADD_ALL_CIPHERS(session);
+       ADD_ALL_COMP(session);
+       ADD_ALL_CERTTYPES(session);
+       ADD_ALL_PROTOCOLS(session);
+       ADD_ALL_MACS(session);
+       ADD_ALL_KX(session);
+       gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred);
+       _gnutls_record_set_default_version( session, 5, 5);
+
+       ret = do_handshake( session);
+       return ret;
+}
+
 void _gnutls_rsa_pms_set_version(gnutls_session session, unsigned char major,
         unsigned char minor);
 
index 52eed9e1dc8c86df8bc8e47d5eee7de8c44fe6b8..b30b2cb5eda21842c55fa1c815f28110af85e3e2 100644 (file)
@@ -28,6 +28,7 @@ int test_certificate( gnutls_session state);
 int test_server_cas( gnutls_session state);
 int test_session_resume2( gnutls_session state);
 int test_rsa_pms_version_check( gnutls_session session);
+int test_version_oob( gnutls_session session);
 
 #define GERR(ret) fprintf(stderr, "*** Error: %s\n", gnutls_strerror(ret))
 
index ac54d61012fa068c36620d5d801ec4254ed38d6d..a61f74d12cb8c280cd234dcd6a8f7cb8811ed771 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *      Copyright (C) 2000,2001,2002 Nikos Mavroyanopoulos
+ * Copyright (C) 2000,2001,2002,2003 Nikos Mavroyanopoulos
  *
  * This file is part of GNUTLS.
  *
@@ -89,6 +89,7 @@ static const TLS_TEST tls_tests[] = {
        { "whether the server ignores the RSA PMS version", test_rsa_pms_version_check, "yes", "no", "dunno"},
        { "whether the server can accept Hello Extensions", test_hello_extension, "yes", "no", "dunno"},
        { "whether the server can accept cipher suites not in SSL 3.0 spec", test_unknown_ciphersuites, "yes", "no", "dunno"},
+       { "whether the server can accept a bogus TLS record version in the client hello", test_version_oob, "yes", "no", "dunno"},
        { "for certificate information", test_certificate, "", "", "" },
        { "for trusted CAs", test_server_cas, "", "", "" },
        { "whether the server understands TLS closure alerts", test_bye, "yes", "no", "partially"},