pki(3tcl)

๐Ÿ“ฆ
version 2.0 ยท 3 versions
, in debian trixie, ubuntu questing, ubuntu resolute, ubuntu stonking

๐ŸŒธ 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:

  1. "openssl rsautl -encrypt" == "::pki::encrypt -binary -pub"
  2. "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:

  1. "openssl rsautl -decrypt" == "::pki::decrypt -binary -priv"
  2. "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 information algo has to be specified if and only if the pki::sign that generated the signedmessage was 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. ๐ŸŒˆ

  • bitlength is the length of the public key modulus.
  • exponent should 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 the cert argument 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 only rsa is 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 the extensions dictionary in the documentation for parse_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.
  • notBefore and notAfter โ€” should contain the time before and after which (respectively) the certificate should be considered invalid. The time should be encoded as something clock format will accept (i.e., the results of clock seconds and clock add). โฐ
  • isCA โ€” a boolean argument describing whether or not the signed certificate should be a CA certificate. If specified as true, the "id-ce-basicConstraints" extension is added, with the arguments of "critical" being true, "allowCA" being true, and caDepth being -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 critical argument 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 allowCA argument specifies, as a boolean value, whether or not we can be used as a certificate authority (CA).
    • The caDepth argument indicates how many children CAs can be children of this CA, in a depth-wise fashion. A value of "0" for caDepth means that this CA cannot sign a CA certificate and have the result be valid. A value of "-1" indicates infinite depth.

...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:

  1. Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile [https://www.rfc-editor.org/rfc/rfc5280]
  2. New ASN.1 Modules for the Public Key Infrastructure Using X.509 (PKIX) [https://www.rfc-editor.org/rfc/rfc5912]
  3. 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 (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