Check-in [7265279af2]
Overview
Comment:Added more X509 certificate status info, show algorithm names, list used extensions, etc.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | status_x509
Files: files | file ages | folders
SHA3-256: 7265279af2138ca838d7a2ff73dbde3a8a0c25b290132afb9acf667c6369380c
User & Date: bohagan on 2023-06-11 02:27:41
Other Links: branch diff | manifest | tags
Context
2023-06-11
20:12
Optimized get X509 certificate extensions check-in: eccad70fa9 user: bohagan tags: status_x509
02:27
Added more X509 certificate status info, show algorithm names, list used extensions, etc. check-in: 7265279af2 user: bohagan tags: status_x509
2023-06-10
21:25
Added master key, is server, and ticket lifetime to connection status. Reordered connection status results for better grouping. check-in: 4e75be42e6 user: bohagan tags: status_x509
Changes
230
231
232
233
234
235
236








237




238

239
240
241

242
243
244
245
246
247
248










249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
        connected peer. If the result is an empty list then the
        SSL handshake has not yet completed.
        If <em>-local</em> is given, then the certificate information
        is the one used locally.</dd>

<blockquote>
    <dl>








        <dt><strong>issuer</strong> <em>dn</em></dt>




        <dd>The distinguished name (DN) of the certificate

            issuer.</dd>
        <dt><strong>subject</strong> <em>dn</em></dt>
        <dd>The distinguished name (DN) of the certificate

            subject.</dd>
        <dt><strong>notBefore</strong> <em>date</em></dt>
        <dd>The begin date for the validity of the certificate.</dd>
        <dt><strong>notAfter</strong> <em>date</em></dt>
        <dd>The expiry date for the certificate.</dd>
        <dt><strong>serial</strong> <em>n</em></dt>
        <dd>The serial number of the certificate.</dd>










        <dt><strong>cipher</strong> <em>cipher</em></dt>
        <dd>The current cipher in use between the client and
            server channels.</dd>
        <dt><strong>sbits</strong> <em>n</em></dt>
        <dd>The number of bits used for the session key.</dd>
        <dt><strong>certificate</strong> <em>cert</em></dt>
        <dd>The PEM encoded certificate.</dd>
        <dt><strong>sha1_hash</strong> <em>hash</em></dt>
        <dd>The SHA1 hash of the certificate.</dd>
        <dt><strong>sha256_hash</strong> <em>hash</em></dt>
        <dd>The SHA256 hash of the certificate.</dd>
        <dt><strong>validation</strong> <em>result</em></dt>
        <dd>Certificate validation result.</dd>
        <dt><strong>alpn</strong> <em>protocol</em></dt>
        <dd>The protocol selected after Application-Layer Protocol
	    Negotiation (ALPN).</dd>
        <dt><strong>version</strong> <em>value</em></dt>
        <dd>The protocol version used for the connection:
	  SSLv2, SSLv3, TLSv1, TLSv1.1, TLSv1.2, TLSv1.3, or unknown</dd>
    </dl>
</blockquote>

    <dt><a name="tls::connection"><strong>tls::connection</strong>
    <em>channel</em></a></dt>







>
>
>
>
>
>
>
>
|
>
>
>
>
|
>
|

|
>
|






>
>
>
>
>
>
>
>
>
>



<
<
<
<
<
<
<
<





|







230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275








276
277
278
279
280
281
282
283
284
285
286
287
288
        connected peer. If the result is an empty list then the
        SSL handshake has not yet completed.
        If <em>-local</em> is given, then the certificate information
        is the one used locally.</dd>

<blockquote>
    <dl>
        <dt><strong>version</strong> <em>value</em></dt>
        <dd>The certification version</dd>
        <dt><strong>signature_algorithm</strong> <em>algorithm</em></dt>
        <dd>Cipher algorithm used for certificate signature.</dd>
        <dt><strong>digest</strong> <em>version</em></dt>
        <dd>Certificate signature digest.</dd>
        <dt><strong>public_key_algorithm</strong> <em>algorithm</em></dt>
        <dd>Certificate signature public key algorithm.</dd>
        <dt><strong>bits</strong> <em>n</em></dt>
        <dd>Number of bits used for certificate signature key</dd>
        <dt><strong>self_signed</strong> <em>boolean</em></dt>
        <dd>Is certificate signature self signed.</dd>
        <dt><strong>sha1_hash</strong> <em>hash</em></dt>
        <dd>The SHA1 hash of the certificate.</dd>
        <dt><strong>sha256_hash</strong> <em>hash</em></dt>
        <dd>The SHA256 hash of the certificate.</dd>
        <dt><strong>subject</strong> <em>dn</em></dt>
        <dd>The distinguished name (DN) of the certificate subject.</dd>
        <dt><strong>issuer</strong> <em>dn</em></dt>
        <dd>The distinguished name (DN) of the certificate issuer.</dd>
        <dt><strong>notBefore</strong> <em>date</em></dt>
        <dd>The begin date for the validity of the certificate.</dd>
        <dt><strong>notAfter</strong> <em>date</em></dt>
        <dd>The expiry date for the certificate.</dd>
        <dt><strong>serial</strong> <em>n</em></dt>
        <dd>The serial number of the certificate.</dd>
        <dt><strong>certificate</strong> <em>cert</em></dt>
        <dd>The PEM encoded certificate.</dd>
        <dt><strong>num_extensions</strong> <em>n</em></dt>
        <dd>Number of certificate extensions.</dd>
        <dt><strong>extensions</strong> <em>list</em></dt>
        <dd>List of certificate extension names.</dd>
        <dt><strong>peername</strong> <em>name</em></dt>
        <dd>The peername from the certificate.</dd>
        <dt><strong>sbits</strong> <em>n</em></dt>
        <dd>The number of bits used for the session key.</dd>
        <dt><strong>cipher</strong> <em>cipher</em></dt>
        <dd>The current cipher in use between the client and
            server channels.</dd>








        <dt><strong>validation</strong> <em>result</em></dt>
        <dd>Certificate validation result.</dd>
        <dt><strong>alpn</strong> <em>protocol</em></dt>
        <dd>The protocol selected after Application-Layer Protocol
	    Negotiation (ALPN).</dd>
        <dt><strong>protocol</strong> <em>value</em></dt>
        <dd>The protocol version used for the connection:
	  SSLv2, SSLv3, TLSv1, TLSv1.1, TLSv1.2, TLSv1.3, or unknown</dd>
    </dl>
</blockquote>

    <dt><a name="tls::connection"><strong>tls::connection</strong>
    <em>channel</em></a></dt>
455
456
457
458
459
460
461

462
463
464
465
466
467
468
	<dd>
	  This form of callback is invoked when the server receives the SNI
	  header from the client where <i>servername</i> is the client
	  specified servername. Used to allow multiple names for
	  same server so the right certificate can be used.
	</dd>


	<br>

	<dt>
	  <strong>verify</strong> <em>channel depth cert status error</em>
	</dt>
	<dd>
	  This form of callback is invoked by the OpenSSL function







>







471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
	<dd>
	  This form of callback is invoked when the server receives the SNI
	  header from the client where <i>servername</i> is the client
	  specified servername. Used to allow multiple names for
	  same server so the right certificate can be used.
	</dd>

	<br>
	<br>

	<dt>
	  <strong>verify</strong> <em>channel depth cert status error</em>
	</dt>
	<dd>
	  This form of callback is invoked by the OpenSSL function
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487

    /* Session id */
    session_id = SSL_SESSION_get_id(session, &ulen);
    Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewByteArrayObj(session_id, (int) ulen));

    /* Session ticket */
    SSL_SESSION_get0_ticket(session, &ticket, &len2);
    Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewStringObj(ticket, (int)len2));

    /* Lifetime - number of seconds */
    Tcl_ListObjAppendElement(interp, cmdPtr,
	Tcl_NewLongObj((long) SSL_SESSION_get_ticket_lifetime_hint(session)));

    Tcl_Preserve((ClientData) interp);
    Tcl_Preserve((ClientData) statePtr);







|







473
474
475
476
477
478
479
480
481
482
483
484
485
486
487

    /* Session id */
    session_id = SSL_SESSION_get_id(session, &ulen);
    Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewByteArrayObj(session_id, (int) ulen));

    /* Session ticket */
    SSL_SESSION_get0_ticket(session, &ticket, &len2);
    Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewByteArrayObj(ticket, (int) len2));

    /* Lifetime - number of seconds */
    Tcl_ListObjAppendElement(interp, cmdPtr,
	Tcl_NewLongObj((long) SSL_SESSION_get_ticket_lifetime_hint(session)));

    Tcl_Preserve((ClientData) interp);
    Tcl_Preserve((ClientData) statePtr);
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
        return SSL_CLIENT_HELLO_ERROR;
    }
    remaining = len;
    servername = (const char *)p;

    cmdPtr = Tcl_DuplicateObj(statePtr->callback);
    Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewStringObj("hello", -1));
    Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewStringObj(servername, (int)len));

    Tcl_Preserve((ClientData) interp);
    Tcl_Preserve((ClientData) statePtr);

    Tcl_IncrRefCount(cmdPtr);
    code = Tcl_EvalObjEx(interp, cmdPtr, TCL_EVAL_GLOBAL);
    if (code != TCL_OK) {







|







713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
        return SSL_CLIENT_HELLO_ERROR;
    }
    remaining = len;
    servername = (const char *)p;

    cmdPtr = Tcl_DuplicateObj(statePtr->callback);
    Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewStringObj("hello", -1));
    Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewStringObj(servername, (int) len));

    Tcl_Preserve((ClientData) interp);
    Tcl_Preserve((ClientData) statePtr);

    Tcl_IncrRefCount(cmdPtr);
    code = Tcl_EvalObjEx(interp, cmdPtr, TCL_EVAL_GLOBAL);
    if (code != TCL_OK) {
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
	proto = "ok";
    }
    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj(proto, -1));

    /* Report the selected protocol as a result of the negotiation */
    SSL_get0_alpn_selected(statePtr->ssl, &proto, &len);
    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("alpn", -1));
    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj((char *)proto, (int)len));
    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("protocol", -1));
    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj(SSL_get_version(statePtr->ssl), -1));

    Tcl_SetObjResult(interp, objPtr);
    return TCL_OK;
	clientData = clientData;
}







|







1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
	proto = "ok";
    }
    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj(proto, -1));

    /* Report the selected protocol as a result of the negotiation */
    SSL_get0_alpn_selected(statePtr->ssl, &proto, &len);
    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("alpn", -1));
    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj((char *)proto, (int) len));
    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("protocol", -1));
    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj(SSL_get_version(statePtr->ssl), -1));

    Tcl_SetObjResult(interp, objPtr);
    return TCL_OK;
	clientData = clientData;
}
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
	const unsigned char *ticket;
	size_t len2;
	unsigned int ulen;
	const unsigned char *session_id;
	char buffer[SSL_MAX_MASTER_KEY_LENGTH];

	/* Report the selected protocol as a result of the ALPN negotiation */
	SSL_SESSION_get0_alpn_selected(session, &proto, &len);
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("alpn", -1));
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj((char *)proto, (int) len));

	/* Peer */
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("peer", -1));
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj(SSL_SESSION_get0_peer(session), -1));

	/* Resumable session */
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("resumable", -1));
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewIntObj(SSL_SESSION_is_resumable(session)));

	/* Start time */
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("start_time", -1));
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewLongObj(SSL_SESSION_get_time(session)));

	/* Timeout value */
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("timeout", -1));
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewLongObj(SSL_SESSION_get_timeout(session)));

	/* Lifetime hint */
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("lifetime", -1));
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewLongObj(SSL_SESSION_get_ticket_lifetime_hint(session)));

	/* Session id */
	session_id = SSL_SESSION_get_id(session, &ulen);
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("session_id", -1));
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewByteArrayObj(session_id, (int) ulen));







|

|
<
<
<
<





|



|



|







1980
1981
1982
1983
1984
1985
1986
1987
1988
1989




1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
	const unsigned char *ticket;
	size_t len2;
	unsigned int ulen;
	const unsigned char *session_id;
	char buffer[SSL_MAX_MASTER_KEY_LENGTH];

	/* Report the selected protocol as a result of the ALPN negotiation */
	SSL_SESSION_get0_alpn_selected(session, &proto, &len2);
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("alpn", -1));
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj((char *)proto, (int) len2));





	/* Resumable session */
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("resumable", -1));
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewIntObj(SSL_SESSION_is_resumable(session)));

	/* Session start time (seconds since epoch) */
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("start_time", -1));
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewLongObj(SSL_SESSION_get_time(session)));

	/* Timeout value - SSL_CTX_get_timeout (in seconds) */
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("timeout", -1));
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewLongObj(SSL_SESSION_get_timeout(session)));

	/* Session ticket lifetime hint (in seconds) */
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("lifetime", -1));
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewLongObj(SSL_SESSION_get_ticket_lifetime_hint(session)));

	/* Session id */
	session_id = SSL_SESSION_get_id(session, &ulen);
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("session_id", -1));
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewByteArrayObj(session_id, (int) ulen));
2549
2550
2551
2552
2553
2554
2555

2556
2557
2558
2559
2560
2561
2562
    locks = malloc(sizeof(*locks) * num_locks);
    memset(locks, 0, sizeof(*locks) * num_locks);
#endif

    /* Initialize BOTH libcrypto and libssl. */
    OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS | OPENSSL_INIT_LOAD_CRYPTO_STRINGS
	| OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS, NULL);


    BIO_new_tcl(NULL, 0);

#if 0
    /*
     * XXX:TODO: Remove this code and replace it with a check
     * for enough entropy and do not try to create our own







>







2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
    locks = malloc(sizeof(*locks) * num_locks);
    memset(locks, 0, sizeof(*locks) * num_locks);
#endif

    /* Initialize BOTH libcrypto and libssl. */
    OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS | OPENSSL_INIT_LOAD_CRYPTO_STRINGS
	| OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS, NULL);


    BIO_new_tcl(NULL, 0);

#if 0
    /*
     * XXX:TODO: Remove this code and replace it with a check
     * for enough entropy and do not try to create our own
89
90
91
92
93
94
95

96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113

114
115
116
117
118
119
120
 */

#define CERT_STR_SIZE 16384

Tcl_Obj*
Tls_NewX509Obj(Tcl_Interp *interp, X509 *cert) {
    Tcl_Obj *certPtr = Tcl_NewListObj(0, NULL);

    BIO *bio;
    int n;
    unsigned long flags;
    char subject[BUFSIZ];
    char issuer[BUFSIZ];
    char serial[BUFSIZ];
    char notBefore[BUFSIZ];
    char notAfter[BUFSIZ];
    char certStr[CERT_STR_SIZE], *certStr_p;
    int certStr_len, toRead;
    char sha1_hash_ascii[SHA_DIGEST_LENGTH * 2 + 1];
    unsigned char sha1_hash_binary[SHA_DIGEST_LENGTH];
    char sha256_hash_ascii[SHA256_DIGEST_LENGTH * 2 + 1];
    unsigned char sha256_hash_binary[SHA256_DIGEST_LENGTH];
    const char *shachars="0123456789ABCDEF";
    int nid, pknid, bits;
    long version;
    uint32_t xflags;


    sha1_hash_ascii[SHA_DIGEST_LENGTH * 2] = '\0';
    sha256_hash_ascii[SHA256_DIGEST_LENGTH * 2] = '\0';

    certStr[0] = 0;
    if ((bio = BIO_new(BIO_s_mem())) == NULL) {
	subject[0] = 0;







>















|
<

>







89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112

113
114
115
116
117
118
119
120
121
 */

#define CERT_STR_SIZE 16384

Tcl_Obj*
Tls_NewX509Obj(Tcl_Interp *interp, X509 *cert) {
    Tcl_Obj *certPtr = Tcl_NewListObj(0, NULL);
    Tcl_Obj *extsPtr = Tcl_NewListObj(0, NULL);
    BIO *bio;
    int n;
    unsigned long flags;
    char subject[BUFSIZ];
    char issuer[BUFSIZ];
    char serial[BUFSIZ];
    char notBefore[BUFSIZ];
    char notAfter[BUFSIZ];
    char certStr[CERT_STR_SIZE], *certStr_p;
    int certStr_len, toRead;
    char sha1_hash_ascii[SHA_DIGEST_LENGTH * 2 + 1];
    unsigned char sha1_hash_binary[SHA_DIGEST_LENGTH];
    char sha256_hash_ascii[SHA256_DIGEST_LENGTH * 2 + 1];
    unsigned char sha256_hash_binary[SHA256_DIGEST_LENGTH];
    const char *shachars="0123456789ABCDEF";
    int nid, pknid, bits, num_of_exts;

    uint32_t xflags;
    const STACK_OF(X509_EXTENSION) *exts;

    sha1_hash_ascii[SHA_DIGEST_LENGTH * 2] = '\0';
    sha256_hash_ascii[SHA256_DIGEST_LENGTH * 2] = '\0';

    certStr[0] = 0;
    if ((bio = BIO_new(BIO_s_mem())) == NULL) {
	subject[0] = 0;
167
168
169
170
171
172
173
174
175
176
177
178
179
180

181
182
183
184
185
186
187
188
189








190
191
192
193
194
195
196
    }

    strcpy(notBefore, ASN1_UTCTIME_tostr(X509_getm_notBefore(cert)));
    strcpy(notAfter, ASN1_UTCTIME_tostr(X509_getm_notAfter(cert)));

    /* Version */
    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("version", -1));
    version = X509_get_version(cert)+1;
    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewLongObj(version));

    /* Signature NID */
    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("signature_nid", -1));
    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewIntObj(X509_get_signature_nid(cert)));
 

    if (X509_get_signature_info(cert, &nid, &pknid, &bits, &xflags) == 1) {
	Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("digest_nid", -1));
	Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewIntObj(nid));
	Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("public_key_nid", -1));
	Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewIntObj(pknid));
	Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("bits", -1));
	Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewIntObj(bits));
	Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("extension_flags", -1));
	Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewIntObj(xflags));








    }
 
    /* SHA1 - DER representation*/
    X509_digest(cert, EVP_sha1(), sha1_hash_binary, NULL);
    for (int n = 0; n < SHA_DIGEST_LENGTH; n++) {
        sha1_hash_ascii[n*2]   = shachars[(sha1_hash_binary[n] & 0xF0) >> 4];
        sha1_hash_ascii[n*2+1] = shachars[(sha1_hash_binary[n] & 0x0F)];







<
|

|
|
|

>

|
|
|
|




>
>
>
>
>
>
>
>







168
169
170
171
172
173
174

175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
    }

    strcpy(notBefore, ASN1_UTCTIME_tostr(X509_getm_notBefore(cert)));
    strcpy(notAfter, ASN1_UTCTIME_tostr(X509_getm_notAfter(cert)));

    /* Version */
    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("version", -1));

    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewLongObj(X509_get_version(cert)+1));

    /* Signature algorithm */
    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("signature_algorithm", -1));
    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(OBJ_nid2ln(X509_get_signature_nid(cert)),-1));
 
    /* Information about the signature of certificate cert */
    if (X509_get_signature_info(cert, &nid, &pknid, &bits, &xflags) == 1) {
	Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("digest", -1));
	Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(OBJ_nid2ln(nid),-1));
	Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("public_key_algorithm", -1));
	Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(OBJ_nid2ln(pknid),-1));
	Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("bits", -1));
	Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewIntObj(bits));
	Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("extension_flags", -1));
	Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewIntObj(xflags));
	
	if (pknid == NID_rsaEncryption || pknid == NID_dsa) {
	    EVP_PKEY *pkey = X509_get_pubkey(cert);
	}
	
	/* Check if cert was issued by CA cert issuer or self signed */
	Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("self_signed", -1));
	Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewBooleanObj(X509_check_issued(cert, cert) == X509_V_OK));
    }
 
    /* SHA1 - DER representation*/
    X509_digest(cert, EVP_sha1(), sha1_hash_binary, NULL);
    for (int n = 0; n < SHA_DIGEST_LENGTH; n++) {
        sha1_hash_ascii[n*2]   = shachars[(sha1_hash_binary[n] & 0xF0) >> 4];
        sha1_hash_ascii[n*2+1] = shachars[(sha1_hash_binary[n] & 0x0F)];
221
222
223
224
225
226
227















228
229

    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("serial", -1));
    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj( serial, -1));

    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("certificate", -1));
    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj( certStr, -1));
















    return certPtr;
}







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253

    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("serial", -1));
    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj( serial, -1));

    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("certificate", -1));
    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj( certStr, -1));

    num_of_exts = X509_get_ext_count(cert);
    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("num_extensions", -1));
    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewIntObj(num_of_exts));

    /* Get extensions */
    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("extensions", -1));
    exts = X509_get0_extensions(cert);
    for (int i=0; i < num_of_exts; i++) {
	X509_EXTENSION *ex = sk_X509_EXTENSION_value(exts, i);
	ASN1_OBJECT *obj = X509_EXTENSION_get_object(ex);
	unsigned nid2 = OBJ_obj2nid(obj);
	Tcl_ListObjAppendElement(interp, extsPtr, Tcl_NewStringObj(OBJ_nid2ln(nid2), -1));
    }
    Tcl_ListObjAppendElement(interp, certPtr, extsPtr);

    return certPtr;
}