From Newsgroup: comp.lang.tcl
Hello everyone,
I have a question for those who have written code using pki: have any of you had pki::x509::verify_cert suddenly begin failing certs, even when the trust has indeed been established, the certs are current, and-- most importantly--
an independent check using "openssl verify -CAfile..." (or some other similar utility) shows that the cert _is_ valid?
I've condensed what I'm experiencing into the test example code below. I've commented the code with _MY_ understanding of what is going on-- but my understanding may be wrong, which may itself be the problem.
But... this _used_ to work...
1) Set up my own Root CA:
-Generate the CA keys (pki::rsa::generate);
-Use those keys to generate a Cert Signing Request for a cert
(pki::pkcs::create_csr/parse_csr);
-Apply those same keys to the CCR to (Self-)sign and create the x509
cert for the CA (::pki::x509::create_cert);
-Save the Root CA x509 cert to the file "example_root_ca.crt"
2) Provision a user certificate signed by the Root CA:
-Generate the user keys (pki::rsa::generate);
-Use the user keys to generate a Cert Signing Request for the user cert
(pki::pkcs::create_csr/parse_csr);
-Sign the user CCR with the CA keys and create the x506 cert for the
user (::pki::x509::create_cert);
-Save the user x509 cert to the file "server.example.com.crt"
3) Check the trust of the user cert against the CA cert
(pki::x509::verify_cert). It should return _true_. But it doesn't, not
anymore! (returns false).
At this point, I look to see what OpenSSL has to say about the x509 certs:
--> openssl verify -CAfile example_root_ca.crt server.example.com.crt
--> server.example.com.crt: OK
These results are identical on my Xubuntu 24.04.4 LTS and MacOS 15.7.4 (Sequoia) workstations, and Ubuntu Server 24.04.4 LTS, all with Tcl8.6 and pki at version 0.20. I have not yet had the opportunity to try the below test example code on Windows, but it may be significant that the original pki code on which the test is based is still functioning on Windows 10, but has since failed on Windows 11 (where it had previously functioned properly).
Anyone else experienced or is experiencing something like this? Or is it just happening to me?
With Gratitude,
-Jerry O.
(Please first reverse the letters in my address domain if replying direct.)
###################### TEST EXAMPLE TCL CODE FOLLOWS #######################
#!/bin/bash
# Run tclsh from user PATH \
exec tclsh "$0" ${1+"$@"}
# name of program is $argv0
# number of arguments is $argc
# argument LIST is $argv; can access using lindex
#
# refer to the paper:
#
# Public Key Infrastructure and the Tool Command Language
# Roy S. Keene
# Jemimah Ruhala
# September 23rd, 2013
# #
https://tca1.tcl-lang.org/tcl2013/Proceedings-2013/RoyKeene/pki-and-tcl-v2.pdf #
package require pki
# CREATE THE ROOT CA
# generate the CA private and public keys
#set ca_key [::pki::rsa::generate 2048]
set ca_keys [::pki::rsa::generate 512] ; # for faster testing
# ::pki::rsa::generate returns a dict with dictionary keys:
# p, l, d, q, e, type, n
#
# l : key length as was specified by caller (2048)
# type : rsa
#
# p, q : are the two prime numbers
#
# n : is the product ( p * q )
# e : is the exponent, default is 0x10001 (65537) unless specified in call-- # ADVISED NOT TO CHANGE.
#
# *** PRESENTED TOGETHER n AND e MAKE THE PUBLIC KEY ***
#
# d : *** THE PRIVATE KEY ***
# save the CA keys to a file
set the_file [open "example_root_ca.keys" w]
puts $the_file $ca_keys
close $the_file
# define the CA cert attributes
set subject [list C "US" O "Example Org" CN "Example Root CA"]
set serial_number [clock seconds] ; # acts as a simple unique id
set not_before [clock seconds]
set not_after [clock add [clock seconds] 10 years]
# right now no extensions (this is taken care of by ::pki, see man page), so
# leave as empty list
set extensions [list]
# create a Certificate Signing Request for the CA using ::pki::pkcs::create_csr # a cert signing request made by an entity requires both that entity's public # and private keys. in this case, the entity is the CA itself, so use the
# $ca_keys generated earlier. Also, a cert requires the subject attribute, and # ::pki::pkcs::create_csr expects a list for this as was defined in the
# CA cert attributes code above.
set ca_csr [::pki::pkcs::create_csr $ca_keys $subject 1]
# ::pki::x509::create_cert expects the signing request to be parsed.
# ::pki::pkcs::parse_csr returns a dict containing l, subject, e, n, type,
# BUT DOES NOT INCLUDE d (THE PRIVATE KEY)!
set parsed_ca_csr [::pki::pkcs::parse_csr $ca_csr]
# ::pki::x509::create_cert also expects the CA "cert" doing the signing to be
# parsed into a dict with keys l, subject, e, n, type, AND d (the private key). #
# $ca_keys already has l, e, n, type, d, but no subject
#
# $parsed_ca_csr has l, subject, e, n, type, but no d
#
# there are two choices then:
# choice 1: take ca_keys and set a new key named "subject" with value
# { C="US" O="Example Org" CN="Example Root CA" ...etc }
# and use that,
# OR
# choice 2: take parsed_ca_csr and set a new key named "d" with value d from
# $ca_keys and use that instead
#
# I prefer choice 2:
set parsed_ca_keys $parsed_ca_csr
dict set parsed_ca_keys d [dict get $ca_keys d]
# create the certificate (an actual x509) for the CA, signed by the CA itself
# (see the tcllib pki man page for the explanation of the first "1" and the
# internal extensions setting that results from it)
set ca_cert [::pki::x509::create_cert \
$parsed_ca_csr \
$parsed_ca_keys\
$serial_number \
$not_before \
$not_after \
1 \
$extensions \
1
]
# save the CA cert to a file for later analysis with OpenSSL verify command
set the_file [open "example_root_ca.crt" w]
puts $the_file $ca_cert
close $the_file
# CREATE A USER CERT AND SIGN IT WITH THE ROOT CA CERT
# generate user Private Key
#set user_keys [::pki::rsa::generate 2048]
set user_keys [::pki::rsa::generate 512] ; # for faster testing
# save the user keys to a file
set the_file [open "server.example.com.keys" w]
puts $the_file $user_keys
close $the_file
# define the user cert attributes
set user_subject [list C "US" O "Example Org" CN "server.example.com"]
set user_serial_number [clock seconds] ; # acts as a simple unique id
set user_not_before [clock seconds]
set user_not_after [clock add [clock seconds] 1 year]
# create a Certificate Signing Request for the user, and parse it
set user_csr [pki::pkcs::create_csr $user_keys $user_subject 1]
set parsed_user_csr [::pki::pkcs::parse_csr $user_csr]
# create the user certificate (an actual x509) signed by the CA
# (note the "0" here instead of "1"-- see the tcllib pki man page)
set user_cert [::pki::x509::create_cert \
$parsed_user_csr \
$parsed_ca_keys\
$user_serial_number \
$user_not_before \
$user_not_after \
0 \
[list] \
1
]
# save the user cert to a file for later analysis with OpenSSL verify command set the_file [open "server.example.com.crt" w]
puts $the_file $user_cert
# check that the user cert validates against the CA
set trusted_cert [pki::x509::parse_cert $ca_cert]
set supplicant_cert [pki::x509::parse_cert $user_cert]
set status [pki::x509::verify_cert $supplicant_cert [list $trusted_cert]]
puts "pki::x509::verify_cert return value (true = pass, false = fail): $status" exit
# compare the result to the command line output of:
# openssl verify -CAfile example_root_ca.crt server.example.com.crt
# if different, WHY?
--- Synchronet 3.21d-Linux NewsLink 1.2