pki(3tcl)
๐ธ pki โ the pki(3tcl) manual, bestie edition ๐ธ
okay so this is the man page for pki, from the public key encryption corner of the Tcl universe ๐ it lives in section 3tcl (iykyk). grab a snack, we're doing cryptography.
โจ NAME โจ
pki โ Implementation of the public key cipher ๐๐
โจ SYNOPSIS โจ
first things first, you gotta have the right Tcl on deck:
package require Tcl 8.5 9
package require pki ?0.22?
and now the actual commands, all lined up and gorgeous:
::pki::encrypt ?-binary? ?-hex? ?-pad? ?-nopad? ?-priv? ?-pub? ?--? input key
::pki::decrypt ?-binary? ?-hex? ?-unpad? ?-nounpad? ?-priv? ?-pub? ?--? input key
::pki::sign input key ?algo?
::pki::verify signedmessage plaintext key ?algo?
::pki::key key ?password? ?encodePem?
::pki::pkcs::parse_key key ?password?
::pki::x509::parse_cert cert
::pki::rsa::generate bitlength ?exponent?
::pki::x509::verify_cert cert trustedcerts ?intermediatecerts?
::pki::x509::validate_cert cert ?-sign_message dn_of_signer? ?-encrypt_message dn_of_signer? ?-sign_cert dn_to_be_signed ca_depth? ?-ssl dn?
::pki::pkcs::create_csr keylist namelist ?encodePem? ?algo?
::pki::pkcs::parse_csr csr
::pki::x509::create_cert signreqlist cakeylist serial_number notBefore notAfter isCA extensions ?encodePem? ?algo?
the ?s mean optional, bestie โ everything else you actually have to hand over. no skipping. ๐ซถ
โจ DESCRIPTION โจ
๐ COMMANDS ๐
Okay bestie, this is the whole menu of things this package can do for you. Every single one, no skips, no "you'll figure it out". Buckle up. ๐
๐ ::pki::encrypt
::pki::encrypt ?-binary? ?-hex? ?-pad? ?-nopad? ?-priv? ?-pub? ?--? input key
Encrypts a message using PKI (which, realistically, means RSA). โจ
You have to tell it which key to use โ either -priv to encrypt with the private key, or -pub to encrypt with the public key. There's no "whatever, you pick" mode. One of -pub or -priv must be specified, periodt. The default behaviour is to pad and hand you back the result in hex.
Here's the option tea:
-hexโ returns the data encoded as a hexadecimal string. ๐-binaryโ returns the data as a binary string.- If you specify either of these multiple times, the last one specified wins. That's just the rule.
-padโ pads the data per PKCS#1 before it gets encrypted.-nopadโ turns that padding behaviour off.- Same deal: specify them multiple times and the last one you said is the one that counts.
-privโ encrypt with the private key.-pubโ encrypt with the public key.--โ it's in the synopsis, sitting right there at the end of the flags. (That's all the original says about it, so that's all I'm saying. ๐)
The thing you're encrypting is passed as input.
The key parameter โ the whole reason this works โ is a return value from one of these three: ::pki::pkcs::parse_key, ::pki::x509::parse_cert, or ::pki::rsa::generate. Don't just hand it a random string, bestie. ๐ญ
Mapping to OpenSSL's openssl application:
"openssl rsautl -encrypt"=="::pki::encrypt -binary -pub""openssl rsautl -sign"=="::pki::encrypt -binary -priv"
๐ ::pki::decrypt
::pki::decrypt ?-binary? ?-hex? ?-unpad? ?-nounpad? ?-priv? ?-pub? ?--? input key
Decrypts a message using PKI (again, probably RSA). For how all the option handling works, go look at ::pki::encrypt โ it's the same energy, just backwards. ๐
Mapping to OpenSSL's openssl application:
"openssl rsautl -decrypt"=="::pki::decrypt -binary -priv""openssl rsautl -verify"=="::pki::decrypt -binary -pub"
โ๏ธ ::pki::sign
::pki::sign input key ?algo?
Digitally signs the message input using the private key. Iconic behaviour, honestly. ๐ฅ
If algo is omitted, "sha1" is assumed. Possible values for algo include "md5", "sha1", "sha256", and "raw".
Now, the "raw" thing โ listen closely, this is the part people mess up. Specifying "raw" for algo will inhibit the building of an ASN.1 structure that encodes which hashing algorithm was chosen. โ ๏ธ Attention: in this case the corresponding pkgi::verify must be called with algorithm information. Conversely, if you specify a non-"raw" algorithm here, that means the corresponding pkgi::verify invocation has to be made without algorithm information. Get this backwards and it's not gonna work, fr fr.
The input should be the plain text โ the hashing gets performed on it for you. ๐ธ
The key should include the private key. Obviously. ๐ซถ
โ
::pki::verify
::pki::verify signedmessage plaintext key ?algo?
Verifies a digital signature using a public key. Returns true or false. That's the whole output, bestie. ๐
โ ๏ธ Attention: the algorithm informationalgohas to be specified if and only if thepki::signthat generated thesignedmessagewas called with algorithm"raw". That"raw"call inhibited the building of the ASN.1 structure encoding the chosen hashing algorithm โ so you're the one who has to supply it now. Conversely, if a proper algorithm was specified during signing, then you must not specify an algorithm here. Matching set, or it's not a match at all. ๐
๐ ::pki::key
::pki::key key ?password? ?encodePem?
Converts a key structure into a serialized PEM (the default) or DER encoded private key that's suitable for other applications to use. For RSA keys, this means PKCS#1. ๐
๐๏ธ ::pki::pkcs::parse_key
::pki::pkcs::parse_key key ?password?
Converts a PKCS#1 private key into a usable key โ meaning one you can actually pass as an argument to ::pki::encrypt, ::pki::decrypt, ::pki::sign, and ::pki::verify. โจ
๐ ::pki::x509::parse_cert
::pki::x509::parse_cert cert
Converts an X.509 certificate into a usable (public) key. The dictionary it hands back can be used as an argument for ::pki:encrypt, ::pki::decrypt, and ::pki::verify. The cert argument can be either PEM or DER encoded โ either one, she's flexible. ๐
On top of the public keying info, that dictionary also carries these keys, holding certificate content as defined in RFC5280 (https://www.rfc-editor.org/rfc/rfc5280#section-4.1):
subjectโ holds the name of the subject from the certificate.issuerโ holds the name of the issuing CA.serial_numberโ holds the serial number of the certificate.notBeforeโ holds the starting date for certificate validity.notAfterโ holds the ending date for certificate validity.versionโ holds the X.509 version format.extensionsโ holds a dictionary containing the extensions included in the certificate (more on that below).
The dictionary holds additional entries related to keying, too. Those are intended for use with the commands mentioned above for cryptographic operations. ๐
The extensions key in the returned dictionary holds a nested dictionary whose keys correspond to the names (with the same exact case, don't get cute with capitalization) in Certificate Extensions (https://www.rfc-editor.org/rfc/rfc5280#section-4.2) in RFC5280. The format of each value is also based on the ASN.1 structures defined there. Peep the Examples for an illustration. ๐ฆ
๐งฎ ::pki::rsa::generate
::pki::rsa::generate bitlength ?exponent?
Generates a brand new RSA key pair, and the parts of it can be used as arguments for ::pki::encrypt, ::pki::decrypt, ::pki::sign, and ::pki::verify. ๐
bitlengthis the length of the public key modulus.exponentshould generally not be specified unless you really, truly, deep-in-your-soul know what you are doing. Like genuinely. ๐
๐ก๏ธ ::pki::x509::verify_cert
::pki::x509::verify_cert cert trustedcerts ?intermediatecerts?
Verifies that trust can be found between the certificate specified in the cert argument and one of the certificates in the list given in the trustedcerts argument. ๐
Heads up: eventually the chain can be through untrusted certificates listed in the intermediatecerts argument, but this is currently unimplemented. So don't count on it yet, bestie. ๐ญ
The certificates specified in the cert and trustedcerts options should be parsed โ meaning they come from ::pki::x509::parse_cert.
๐ ::pki::x509::validate_cert
::pki::x509::validate_cert cert ?-sign_message dn_of_signer? ?-encrypt_message dn_of_signer? ?-sign_cert dn_to_be_signed ca_depth? ?-ssl dn?
Validates that a certificate is valid to be used in some capacity. If you specify multiple options, they all have to be met for this procedure to return "true". All of them. No partial credit. โจ
Currently, only the -sign_cert option is functional. Its arguments are dn_to_be_signed and ca_depth:
dn_to_be_signedโ the distinguished from the subject of a certificate, used to verify that the certificate specified in thecertargument can sign.ca_depthโ indicates at which depth the verification should be done at. Some certificates are limited in how far down the chain they can be used to verify a given certificate. ๐
๐ ::pki::pkcs::create_csr
::pki::pkcs::create_csr keylist namelist ?encodePem? ?algo?
Generates a certificate signing request from a key pair, specified in the keylist argument. ๐ฅ
The namelist argument is a list of "name" followed by "value" pairs, to be encoded as the requested distinguished name in the CSR.
The encodePem option says whether the result should be PEM encoded or DER encoded. A "true" value means the result gets PEM encoded, while any other value results in the result being DER encoded. DER encoding is the default. ๐ฆ
The algo argument specifies the hashing algorithm to sign this certificate signing request with. The default is "sha1". Other possible values include "md5" and "sha256".
๐ ::pki::pkcs::parse_csr
::pki::pkcs::parse_csr csr
Parses a Certificate Signing Request. The csr argument can be either PEM or DER encoded โ once again, flexible. ๐ธ
The command returns a dictionary that includes these keys:
subjectโ contains the subject name from the CSR.typeโ contains the public key algorithm name. Currently onlyrsais supported.extensionRequestโ contains a dictionary with the contents of the extensionRequest (https://datatracker.ietf.org/doc/html/rfc2986#page-5) information in the CSR. This has the same form as described for theextensionsdictionary in the documentation forparse_cert.
There may be other keys in the dictionary related to the public key algorithm in use. ๐
๐
::pki::x509::create_cert
::pki::x509::create_cert signreqlist cakeylist serial_number notBefore notAfter isCA extensions ?encodePem? ?algo?
Signs a signing request (usually from ::pki::pkcs::create_csr or ::pki::pkcs::parse_csr) with a Certificate Authority (CA) certificate. This is the main character moment of the whole page, honestly. ๐
Here's who's who in the argument lineup:
signreqlistโ should be the parsed signing request.cakeylistโ should be the parsed CA certificate.serial_numberโ should be a serial number unique to this certificate from this certificate authority.notBeforeandnotAfterโ should contain the time before and after which (respectively) the certificate should be considered invalid. The time should be encoded as somethingclock formatwill accept (i.e., the results ofclock secondsandclock add). โฐisCAโ a boolean argument describing whether or not the signed certificate should be a CA certificate. If specified astrue, the"id-ce-basicConstraints"extension is added, with the arguments of"critical"beingtrue,"allowCA"beingtrue, andcaDepthbeing-1(infinite). ๐extensionsโ a list of extensions and their parameters that should be encoded into the created certificate. Currently only one extension is understood:"id-ce-basicConstraints". It accepts three arguments:critical,allowCA,caDepth.- The
criticalargument to this extension (and to any extension) is about whether or not the validator should reject the certificate as invalid if it doesn't understand the extension (if set to"true") or should ignore the extension (if set to"false"). ๐จ - The
allowCAargument specifies, as a boolean value, whether or not we can be used as a certificate authority (CA). - The
caDepthargument indicates how many children CAs can be children of this CA, in a depth-wise fashion. A value of"0"forcaDepthmeans that this CA cannot sign a CA certificate and have the result be valid. A value of"-1"indicates infinite depth.
- The
...and that's the command lineup, bestie โ but we're not done, there's still more page to get through. Keep scrolling. ๐
๐ธ EXAMPLES ๐ธ
okay bestie, watch this โ we're gonna grab a real certificate off www.example.com using the TLS extension, and then dump everything it's got inside. it's giving detective work but make it โจcryptographyโจ.
% set so [tls::socket www.example.com 443]
sock00000229EB84E710
% tls::handshake $so
1
% set status [tls::status $so]
...output not shown...
% set cert_pem [dict get $status certificate]
...output not shown...
% set cert [::pki::x509::parse_cert $cert_pem]
...output not shown...
% dict get $cert subject
C=US, ST=California, L=Los Angeles, O=Internet Corporation for Assigned Names and Numbers, CN=www.example.org
% dict get $cert issuer
C=US, O=DigiCert Inc, CN=DigiCert TLS RSA SHA256 2020 CA1
% clock format [dict get $cert notAfter]
Sun Dec 26 05:29:59 +0530 2021
% set extensions [dict get $cert extensions]
...output not shown...
% dict keys $extensions
authorityKeyIdentifier subjectKeyIdentifier subjectAltName keyUsage extKeyUsage cRLDistributionPoints certificatePolicies authorityInfoAccess id-ce-basicConstraints basicConstraints 1.3.6.1.4.1.11129.2.4.2
dict get $extensions basicConstraints
1 {0 -1}
% dict get $extensions keyUsage
1 {5 digitalSignature keyEncipherment}
% dict get $extensions extKeyUsage
0 {serverAuth clientAuth}
% dict get $extensions subjectAltName
0 {dNSName www.example.org dNSName example.com dNSName example.edu dNSName example.net dNSName example.org dNSName www.example.com dNSName www.example.edu dNSName www.example.net}
% dict get $extensions basicConstraints
1 {0 -1}
% dict get $extensions keyUsage
1 {5 digitalSignature keyEncipherment}
% dict get $extensions extKeyUsage
0 {serverAuth clientAuth}
so yeah, that whole glow-up from raw PEM bytes to a nice tidy dict of subject, issuer, expiry and extensions? iconic. the SAN list is doing the most but we love her ๐
๐ REFERENCES ๐
the receipts, bestie. cite your sources or it didn't happen:
- Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile [https://www.rfc-editor.org/rfc/rfc5280]
- New ASN.1 Modules for the Public Key Infrastructure Using X.509 (PKIX) [https://www.rfc-editor.org/rfc/rfc5912]
- PKCS #10: Certification Request Syntax Specification [https://www.rfc-editor.org/rfc/rfc2986]
๐ AUTHORS ๐
the actual main characters behind all this:
- Roy Keene
- Ashok P. Nadkarni
๐ BUGS, IDEAS, FEEDBACK ๐
ngl, this document and the package it describes will undoubtedly contain bugs and other problems. that's just how it is fr fr โ no software is perfect and we're not pretending otherwise.
so please report them in the category rsa of the Tcllib Trackers: [http://core.tcl.tk/tcllib/reportlist](http://core.tcl.tk/tcllib/reportlist). and if you've got ideas for enhancements for either the package and/or the documentation, send those too โ we want them ๐ซถ
when you're proposing code changes, please provide unified diffs, i.e. the output of diff -u. this is not optional bestie, this is the vibe.
also, important: attachments are strongly preferred over inlined patches. to attach something, go to the Edit form of the ticket right after you create it, then use the left-most button in the secondary navigation bar. that's the whole trick, iykyk โจ
๐ SEE ALSO ๐
go read these too, they're the friend group:
๐ KEYWORDS ๐
the tags, the aesthetic, the searchable lore:
cipher, data integrity, encryption, public key cipher, rsa, security
๐ฆ CATEGORY ๐ฆ
Hashes, checksums, and encryption โ that's the shelf we live on.
๐ COPYRIGHT ๐
Copyright (c) 2010, 2011, 2012, 2013, 2021 - 2024 Roy Keene, Andreas Kupries, Ashok P. Nadkarni
and that's a wrap on pki(3tcl), bestie ๐ซถ this one came from tcllib, version 0.22, dated pki(3tcl) โ go forth and parse some certs, you absolute legend ๐ โจ
๐ฆ where this page comes from
- debian trixie: tcllib 2.0+dfsg-4 ยท Tcl
- ubuntu questing: tcllib 2.0+dfsg-4
- ubuntu resolute: tcllib 2.0+dfsg-5 ยท Tcl
- ubuntu stonking: tcllib 2.0+dfsg-6 ยท Tcl
- Copyright (c) 2010, 2011, 2012, 2013, 2021 - 2024 Roy Keene, Andreas Kupries, Ashok P\&. Nadkarni
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms