Changes On Branch e94d9cae93369db4

Changes In Branch status_x509 Through [e94d9cae93] Excluding Merge-Ins

This is equivalent to a diff from dbe759a0f2 to e94d9cae93

2023-09-01
21:57
Merged status and X509 updates branch into master check-in: 3432ab03a3 user: bohagan tags: trunk
2023-08-02
01:17
Added Certificate Revocation List (CRL) to X509 status. Moved get X509 extension items to end of function. check-in: f22fb82c96 user: bohagan tags: status_x509
2023-08-01
22:42
Added Certificate purposes to X509 status output. Corrected certificate alias get text bug. Refactored code to reduce number of variables and use common buffers for SHA fingerprints. check-in: e94d9cae93 user: bohagan tags: status_x509
2023-07-31
02:17
Added verify depth and mode status to connection status, renamed signatureType and signatureType check-in: 87010ba1d9 user: bohagan tags: status_x509
2023-07-30
03:39
Merged master into branch check-in: 739742d3d4 user: bohagan tags: status_x509
03:21
Merged errors_and_callbacks branch into master check-in: dbe759a0f2 user: bohagan tags: trunk
02:53
Updated default callbacks in tls.tcl file Closed-Leaf check-in: cdb51c799e user: bohagan tags: errors_and_callbacks
2023-07-16
15:05
Merge status and X509 updates branch check-in: 1924dcd361 user: bohagan tags: trunk

252
253
254
255
256
257
258
259
260





261
262
263
264
265
266
267
268
	<dt><strong>protocol</strong> <em>version</em></dt>
	<dd>The protocol version used for the connection:
	    SSL2, SSL3, TLS1, TLS1.1, TLS1.2, TLS1.3, or unknown.</dd>
	<dt><strong>sbits</strong> <em>n</em></dt>
	<dd>The number of bits used for the session key.</dd>
	<dt><strong>signatureHashAlgorithm</strong> <em>algorithm</em></dt>
	<dd>The signature hash algorithm.</dd>
	<dt><strong>signature_type</strong> <em>type</em></dt>
	<dd>The signature type value.</dd>





	<dt><strong>verification</strong> <em>result</em></dt>
	<dd>Certificate verification result.</dd>
	<dt><strong>ca_names</strong> <em>list</em></dt>
	<dd>List of the Certificate Authorities used to create the certificate.</dd>
    </dl>
</blockquote>
<blockquote>
	<b>Certificate Status</b>







|

>
>
>
>
>
|







252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
	<dt><strong>protocol</strong> <em>version</em></dt>
	<dd>The protocol version used for the connection:
	    SSL2, SSL3, TLS1, TLS1.1, TLS1.2, TLS1.3, or unknown.</dd>
	<dt><strong>sbits</strong> <em>n</em></dt>
	<dd>The number of bits used for the session key.</dd>
	<dt><strong>signatureHashAlgorithm</strong> <em>algorithm</em></dt>
	<dd>The signature hash algorithm.</dd>
	<dt><strong>signatureType</strong> <em>type</em></dt>
	<dd>The signature type value.</dd>
	<dt><strong>verifyDepth</strong> <em>n</em></dt>
	<dd>Maximum depth for the certificate chain verification.
	    Default is -1, to check all.</dd>
	<dt><strong>verifyMode</strong> <em>list</em></dt>
	<dd>List of certificate verification modes.</dd>
	<dt><strong>verifyResult</strong> <em>result</em></dt>
	<dd>Certificate verification result.</dd>
	<dt><strong>ca_names</strong> <em>list</em></dt>
	<dd>List of the Certificate Authorities used to create the certificate.</dd>
    </dl>
</blockquote>
<blockquote>
	<b>Certificate Status</b>
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108




























2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
    ciphers = (char*)SSL_get_cipher(statePtr->ssl);
    if ((ciphers != NULL) && (strcmp(ciphers, "(NONE)") != 0)) {
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("cipher", -1));
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj(ciphers, -1));
    }

    /* Verify the X509 certificate presented by the peer */
    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("verification", -1));
    Tcl_ListObjAppendElement(interp, objPtr,
	Tcl_NewStringObj(X509_verify_cert_error_string(SSL_get_verify_result(statePtr->ssl)), -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));

    /* Valid for non-RSA signature and TLS 1.3 */
    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("signatureHashAlgorithm", -1));
    if (objc == 2 ? SSL_get_peer_signature_nid(statePtr->ssl, &nid) : SSL_get_signature_nid(statePtr->ssl, &nid)) {
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj(OBJ_nid2ln(nid), -1));
    } else {
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("", -1));
    }
    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("signature_type", -1));
    if (objc == 2 ? SSL_get_peer_signature_type_nid(statePtr->ssl, &nid) : SSL_get_signature_type_nid(statePtr->ssl, &nid)) {
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj(OBJ_nid2ln(nid), -1));
    } else {
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("", -1));
    }

    Tcl_SetObjResult(interp, objPtr);







|



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














|







2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
    ciphers = (char*)SSL_get_cipher(statePtr->ssl);
    if ((ciphers != NULL) && (strcmp(ciphers, "(NONE)") != 0)) {
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("cipher", -1));
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj(ciphers, -1));
    }

    /* Verify the X509 certificate presented by the peer */
    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("verifyResult", -1));
    Tcl_ListObjAppendElement(interp, objPtr,
	Tcl_NewStringObj(X509_verify_cert_error_string(SSL_get_verify_result(statePtr->ssl)), -1));

    /* Verify mode */
    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("verifyMode", -1));
    /* SSL_CTX_get_verify_mode(ctx) */
    mode = SSL_get_verify_mode(statePtr->ssl);
    if (mode && SSL_VERIFY_NONE) {
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("none", -1));
    } else {
	Tcl_Obj *listObjPtr = Tcl_NewListObj(0, NULL);
	if (mode && SSL_VERIFY_PEER) {
	    Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewStringObj("peer", -1));
	}
	if (mode && SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
	    Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewStringObj("fail if no peer cert", -1));
	}
	if (mode && SSL_VERIFY_CLIENT_ONCE) {
	    Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewStringObj("client once", -1));
	}
	if (mode && SSL_VERIFY_POST_HANDSHAKE) {
	    Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewStringObj("post handshake", -1));
	}
	Tcl_ListObjAppendElement(interp, objPtr, listObjPtr);
    }

    /* Verify mode depth */
    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("verifyDepth", -1));
    /* SSL_CTX_get_verify_depth(ctx) */
    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewIntObj(SSL_get_verify_depth(statePtr->ssl)));

    /* 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));

    /* Valid for non-RSA signature and TLS 1.3 */
    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("signatureHashAlgorithm", -1));
    if (objc == 2 ? SSL_get_peer_signature_nid(statePtr->ssl, &nid) : SSL_get_signature_nid(statePtr->ssl, &nid)) {
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj(OBJ_nid2ln(nid), -1));
    } else {
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("", -1));
    }
    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("signatureType", -1));
    if (objc == 2 ? SSL_get_peer_signature_type_nid(statePtr->ssl, &nid) : SSL_get_signature_type_nid(statePtr->ssl, &nid)) {
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj(OBJ_nid2ln(nid), -1));
    } else {
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("", -1));
    }

    Tcl_SetObjResult(interp, objPtr);
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
}

static int max(int a, int b)
{
    return (a > b) ? a : b;
}

/*
 * ASN1_UTCTIME_tostr --
 */
static char *
ASN1_UTCTIME_tostr(ASN1_UTCTIME *tm)
{
    static char bp[128];
    char *v;
    int gmt=0;
    static char *mon[12]={
        "Jan","Feb","Mar","Apr","May","Jun", "Jul","Aug","Sep","Oct","Nov","Dec"};
    int i;
    int y=0,M=0,d=0,h=0,m=0,s=0;

    i=tm->length;
    v=(char *)tm->data;

    if (i < 10) goto err;
    if (v[i-1] == 'Z') gmt=1;
    for (i=0; i<10; i++)
        if ((v[i] > '9') || (v[i] < '0')) goto err;
    y= (v[0]-'0')*10+(v[1]-'0');
    if (y < 70) y+=100;
    M= (v[2]-'0')*10+(v[3]-'0');
    if ((M > 12) || (M < 1)) goto err;
    d= (v[4]-'0')*10+(v[5]-'0');
    h= (v[6]-'0')*10+(v[7]-'0');
    m=  (v[8]-'0')*10+(v[9]-'0');
    if ((v[10] >= '0') && (v[10] <= '9') && (v[11] >= '0') && (v[11] <= '9'))
        s=  (v[10]-'0')*10+(v[11]-'0');

    sprintf(bp,"%s %2d %02d:%02d:%02d %d%s", mon[M-1],d,h,m,s,y+1900,(gmt)?" GMT":"");
    return bp;
 err:
    return "Bad time value";
}

/*
 * Binary string to hex string
 */
int String_to_Hex(char* input, int len, char *output, int max) {
    int count = 0;

    for (int i = 0; i < len && count < max - 1; i++, count += 2) {







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







29
30
31
32
33
34
35





































36
37
38
39
40
41
42
}

static int max(int a, int b)
{
    return (a > b) ? a : b;
}






































/*
 * Binary string to hex string
 */
int String_to_Hex(char* input, int len, char *output, int max) {
    int count = 0;

    for (int i = 0; i < len && count < max - 1; i++, count += 2) {
88
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
122
123
124
125
126
127
128
129
130
131



132
133
134
135

136
137
138
139
140
141


142
143
144
145
146
147


148
149
150
151
152

153
154
155
156
157
158
159
160
161
162
163
164
165
166
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
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
 *
 *	Tls_NewX509Obj --
 *
 *	------------------------------------------------*
 *	Converts a X509 certificate into a Tcl_Obj
 *	------------------------------------------------*
 *
 *	Sideeffects:
 *		None
 *
 *	Result:
 *		A Tcl List Object representing the provided
 *		X509 certificate.
 *
 *------------------------------------------------------*
 */

#define CERT_STR_SIZE 32768

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 buffer[BUFSIZ];
    char certStr[CERT_STR_SIZE], *certStr_p;
    int certStr_len, toRead;
    unsigned char sha1_hash_binary[SHA_DIGEST_LENGTH];
    unsigned char sha256_hash_binary[SHA256_DIGEST_LENGTH];
    int nid, pknid, bits, num_of_exts, len;
    uint32_t xflags;
    STACK_OF(GENERAL_NAME) *san;

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



    } else {
	flags = XN_FLAG_RFC2253 | ASN1_STRFLGS_UTF8_CONVERT;
	flags &= ~ASN1_STRFLGS_ESC_MSB;


	X509_NAME_print_ex(bio, X509_get_subject_name(cert), 0, flags);
	n = BIO_read(bio, subject, min(BIO_pending(bio), BUFSIZ - 1));
	n = max(n, 0);
	subject[n] = 0;
	(void)BIO_flush(bio);



	X509_NAME_print_ex(bio, X509_get_issuer_name(cert), 0, flags);
	n = BIO_read(bio, issuer, min(BIO_pending(bio), BUFSIZ - 1));
	n = max(n, 0);
	issuer[n] = 0;
	(void)BIO_flush(bio);



	i2a_ASN1_INTEGER(bio, X509_get0_serialNumber(cert));
	n = BIO_read(bio, serial, min(BIO_pending(bio), BUFSIZ - 1));
	n = max(n, 0);
	serial[n] = 0;
	(void)BIO_flush(bio);


        /* Get certificate */
        if (PEM_write_bio_X509(bio, cert)) {
            certStr_p = certStr;
            certStr_len = 0;
            while (1) {
                toRead = min(BIO_pending(bio), CERT_STR_SIZE - certStr_len - 1);
                toRead = min(toRead, BUFSIZ);
                if (toRead == 0) {
                    break;
                }
                dprintf("Reading %i bytes from the certificate...", toRead);
                n = BIO_read(bio, certStr_p, toRead);
                if (n <= 0) {
                    break;
                }
                certStr_len += n;
                certStr_p   += n;
            }
            *certStr_p = '\0';
            (void)BIO_flush(bio);
        }

	/* All */
	if (X509_print_ex(bio, cert, flags, 0)) {
	    char all[65536];
	    n = BIO_read(bio, all, min(BIO_pending(bio), 65535));
	    n = max(n, 0);
	    all[n] = 0;
	    (void)BIO_flush(bio);
	    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("all", -1));
	    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(all, n));
	}















	BIO_free(bio);
    }

    strcpy(notBefore, ASN1_UTCTIME_tostr(X509_get0_notBefore(cert)));
    strcpy(notAfter, ASN1_UTCTIME_tostr(X509_get0_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", -1));
    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(OBJ_nid2ln(X509_get_signature_nid(cert)),-1));
 
    /* SHA1 Fingerprint of cert - DER representation */
    X509_digest(cert, EVP_sha1(), sha1_hash_binary, &len);
    len = String_to_Hex(sha1_hash_binary, len, buffer, BUFSIZ);
    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("sha1_hash", -1));
    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(buffer, len));

    /* SHA256 Fingerprint of cert - DER representation */
    X509_digest(cert, EVP_sha256(), sha256_hash_binary, &len);
    len = String_to_Hex(sha256_hash_binary, len, buffer, BUFSIZ);
    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("sha256_hash", -1));
    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(buffer, len));

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

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







|















|
|






|
<
|
<
<
<


|
<
|
|
|
>
>
>
|
|


>
|
|
<
|
|
|
>
>
|
|
|
<
|
|
>
>
|
|
|
<
|
>



|
|

|
















|



|
<




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




<
<
<







|

|
|




|
|







51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82

83



84
85
86

87
88
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144

145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166



167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
 *
 *	Tls_NewX509Obj --
 *
 *	------------------------------------------------*
 *	Converts a X509 certificate into a Tcl_Obj
 *	------------------------------------------------*
 *
 *	Side effects:
 *		None
 *
 *	Result:
 *		A Tcl List Object representing the provided
 *		X509 certificate.
 *
 *------------------------------------------------------*
 */

#define CERT_STR_SIZE 32768

Tcl_Obj*
Tls_NewX509Obj(Tcl_Interp *interp, X509 *cert) {
    Tcl_Obj *certPtr = Tcl_NewListObj(0, NULL);
    BIO *bio;
    int nid, pknid, bits, num_of_exts, len;
    uint32_t xflags;
    char subject[BUFSIZ];
    char issuer[BUFSIZ];
    char serial[BUFSIZ];
    char notBefore[BUFSIZ];
    char notAfter[BUFSIZ];
    char buffer[BUFSIZ];
    char certStr[CERT_STR_SIZE];

    unsigned char md[EVP_MAX_MD_SIZE];



    STACK_OF(GENERAL_NAME) *san;

    certStr[0]   = 0;

    subject[0]   = 0;
    issuer[0]    = 0;
    serial[0]    = 0;
    notBefore[0] = 0;
    notAfter[0]  = 0;
    if ((bio = BIO_new(BIO_s_mem())) != NULL) {
	int n;
	unsigned long flags = XN_FLAG_RFC2253 | ASN1_STRFLGS_UTF8_CONVERT;
	flags &= ~ASN1_STRFLGS_ESC_MSB;

	/* Get subject name */
	if (X509_NAME_print_ex(bio, X509_get_subject_name(cert), 0, flags) > 0) {
	    n = BIO_read(bio, subject, min(BIO_pending(bio), BUFSIZ - 1));

	    subject[max(n, 0)] = 0;
	    (void)BIO_flush(bio);
	}

	/* Get issuer name */
	if (X509_NAME_print_ex(bio, X509_get_issuer_name(cert), 0, flags) > 0) {
	    n = BIO_read(bio, issuer, min(BIO_pending(bio), BUFSIZ - 1));
	    issuer[max(n, 0)] = 0;

	    (void)BIO_flush(bio);
	}

	/* Get serial number */
	if (i2a_ASN1_INTEGER(bio, X509_get0_serialNumber(cert)) > 0) {
	    n = BIO_read(bio, serial, min(BIO_pending(bio), BUFSIZ - 1));
	    serial[max(n, 0)] = 0;

	    (void)BIO_flush(bio);
	}

        /* Get certificate */
        if (PEM_write_bio_X509(bio, cert)) {
            char *certStr_p = certStr;
            int certStr_len = 0;
            while (1) {
                int toRead = min(BIO_pending(bio), CERT_STR_SIZE - certStr_len - 1);
                toRead = min(toRead, BUFSIZ);
                if (toRead == 0) {
                    break;
                }
                dprintf("Reading %i bytes from the certificate...", toRead);
                n = BIO_read(bio, certStr_p, toRead);
                if (n <= 0) {
                    break;
                }
                certStr_len += n;
                certStr_p   += n;
            }
            *certStr_p = '\0';
            (void)BIO_flush(bio);
        }

	/* Get all cert info */
	if (X509_print_ex(bio, cert, flags, 0)) {
	    char all[65536];
	    n = BIO_read(bio, all, min(BIO_pending(bio), 65535));
	    all[max(n, 0)] = 0;

	    (void)BIO_flush(bio);
	    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("all", -1));
	    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(all, n));
	}

	/* Get Validity - Not Before */
	if (ASN1_TIME_print(bio, X509_get0_notBefore(cert))) {
	    n = BIO_read(bio, notBefore, min(BIO_pending(bio), BUFSIZ - 1));
	    notBefore[max(n, 0)] = 0;
	    (void)BIO_flush(bio);
	}

	/* Get Validity - Not After */
	if (ASN1_TIME_print(bio, X509_get0_notAfter(cert))) {
	    n = BIO_read(bio, notAfter, min(BIO_pending(bio), BUFSIZ - 1));
	    notAfter[max(n, 0)] = 0;
	    (void)BIO_flush(bio);
	}

	BIO_free(bio);
    }




    /* 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", -1));
    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(OBJ_nid2ln(X509_get_signature_nid(cert)),-1));

    /* SHA1 Fingerprint of cert - DER representation */
    X509_digest(cert, EVP_sha1(), md, &len);
    len = String_to_Hex(md, len, buffer, BUFSIZ);
    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("sha1_hash", -1));
    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(buffer, len));

    /* SHA256 Fingerprint of cert - DER representation */
    X509_digest(cert, EVP_sha256(), md, &len);
    len = String_to_Hex(md, len, buffer, BUFSIZ);
    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("sha256_hash", -1));
    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(buffer, len));

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

    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("issuer", -1));
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
	Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(OBJ_nid2ln(nid),-1));
	Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("publicKeyAlgorithm", -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));
	
	/* Public key - X509_get0_pubkey */
	key = X509_get0_pubkey_bitstr(cert);
	len = String_to_Hex(key->data, key->length, buffer, BUFSIZ);
	Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("publicKey", -1));
	Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(buffer, len));
	
	/* 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));
    }

    /* Unique Ids */
    {







|





|







214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
	Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(OBJ_nid2ln(nid),-1));
	Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("publicKeyAlgorithm", -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));

	/* Public key - X509_get0_pubkey */
	key = X509_get0_pubkey_bitstr(cert);
	len = String_to_Hex(key->data, key->length, buffer, BUFSIZ);
	Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("publicKey", -1));
	Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(buffer, len));

	/* 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));
    }

    /* Unique Ids */
    {
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
	    }
	}
	sk_GENERAL_NAME_pop_free(san, GENERAL_NAME_free);
	Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("subjectAltName", -1));
	Tcl_ListObjAppendElement(interp, certPtr, namesPtr);
    }

    /* Certificate Alias  */
    {
	unsigned char *bstring;
	len = 0;
	bstring = X509_alias_get0(cert, &len);
	len = String_to_Hex(bstring, len, buffer, BUFSIZ);
	Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("alias", -1));
	Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(buffer, len));
    }

    /* Get Subject Key id, Authority Key id */
    {
	ASN1_OCTET_STRING *astring;
	/* X509_keyid_get0 */
	astring = X509_get0_subject_key_id(cert);
	Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("subjectKeyIdentifier", -1));
	if (astring != NULL) {
	    len = String_to_Hex((char *)ASN1_STRING_get0_data(astring), ASN1_STRING_length(astring), buffer, BUFSIZ);
	    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewByteArrayObj(buffer, len));
	} else {
	    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("", -1));
	}

	astring = X509_get0_authority_key_id(cert);
	Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("authorityKeyIdentifier", -1));
	if (astring != NULL) {
	    len = String_to_Hex((char *)ASN1_STRING_get0_data(astring), ASN1_STRING_length(astring), buffer, BUFSIZ);
	    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewByteArrayObj(buffer, len));
	} else {
	    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("", -1));
	}
	
	/*  const GENERAL_NAMES *X509_get0_authority_issuer(cert);
	const ASN1_INTEGER *X509_get0_authority_serial(cert); */
    }







|




<

|










|








|







287
288
289
290
291
292
293
294
295
296
297
298

299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
	    }
	}
	sk_GENERAL_NAME_pop_free(san, GENERAL_NAME_free);
	Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("subjectAltName", -1));
	Tcl_ListObjAppendElement(interp, certPtr, namesPtr);
    }

    /* Certificate Alias as UTF-8 string */
    {
	unsigned char *bstring;
	len = 0;
	bstring = X509_alias_get0(cert, &len);

	Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("alias", -1));
	Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj((char *)bstring, len));
    }

    /* Get Subject Key id, Authority Key id */
    {
	ASN1_OCTET_STRING *astring;
	/* X509_keyid_get0 */
	astring = X509_get0_subject_key_id(cert);
	Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("subjectKeyIdentifier", -1));
	if (astring != NULL) {
	    len = String_to_Hex((char *)ASN1_STRING_get0_data(astring), ASN1_STRING_length(astring), buffer, BUFSIZ);
	    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(buffer, len));
	} else {
	    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("", -1));
	}

	astring = X509_get0_authority_key_id(cert);
	Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("authorityKeyIdentifier", -1));
	if (astring != NULL) {
	    len = String_to_Hex((char *)ASN1_STRING_get0_data(astring), ASN1_STRING_length(astring), buffer, BUFSIZ);
	    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(buffer, len));
	} else {
	    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("", -1));
	}
	
	/*  const GENERAL_NAMES *X509_get0_authority_issuer(cert);
	const ASN1_INTEGER *X509_get0_authority_serial(cert); */
    }
385
386
387
388
389
390
391



















392
393
394
	if (sig_nid != NID_undef) {
	    len = String_to_Hex(sig->data, sig->length, buffer, BUFSIZ);
	    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(buffer, len));
	} else {
	    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("", -1));
	}
    }




















    return certPtr;
}







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



358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
	if (sig_nid != NID_undef) {
	    len = String_to_Hex(sig->data, sig->length, buffer, BUFSIZ);
	    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj(buffer, len));
	} else {
	    Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("", -1));
	}
    }

    /* Certificate purposes */
    {
	Tcl_Obj *purpPtr = Tcl_NewListObj(0, NULL);
	for (int j = 0; j < X509_PURPOSE_get_count(); j++) {
	    X509_PURPOSE *ptmp = X509_PURPOSE_get0(j);
	    Tcl_Obj *tmpPtr = Tcl_NewListObj(0, NULL);

	    for (int i = 0; i < 2; i++) {
		int idret = X509_check_purpose(cert, X509_PURPOSE_get_id(ptmp), i);
		Tcl_ListObjAppendElement(interp, tmpPtr, Tcl_NewStringObj(i ? "CA" : "nonCA", -1));
		Tcl_ListObjAppendElement(interp, tmpPtr, Tcl_NewStringObj(idret ? "Yes" : "No", -1));
	    }
	    Tcl_ListObjAppendElement(interp, purpPtr, Tcl_NewStringObj(X509_PURPOSE_get0_name(ptmp), -1));
	    Tcl_ListObjAppendElement(interp, purpPtr, tmpPtr);
	}
	Tcl_ListObjAppendElement(interp, certPtr, Tcl_NewStringObj("certificatePurpose", -1));
	Tcl_ListObjAppendElement(interp, certPtr, purpPtr);
    }

    return certPtr;
}