[//000000001]: # (pki \- public key encryption)
[//000000002]: # (Generated from file 'pki\.man' by tcllib/doctools with format 'markdown')
[//000000003]: # (Copyright © 2010, 2011, 2012, 2013, 2021 Roy Keene, Andreas Kupries, Ashok P\. Nadkarni)
[//000000004]: # (pki\(n\) 0\.10 tcllib "public key encryption")
[ Main Table Of Contents | Table Of Contents | Keyword Index | Categories | Modules | Applications ]
# NAME
pki \- Implementation of the public key cipher
# Table Of Contents
- [Table Of Contents](#toc)
- [Synopsis](#synopsis)
- [Description](#section1)
- [COMMANDS](#section2)
- [EXAMPLES](#section3)
- [REFERENCES](#section4)
- [AUTHORS](#section5)
- [Bugs, Ideas, Feedback](#section6)
- [See Also](#seealso)
- [Keywords](#keywords)
- [Category](#category)
- [Copyright](#copyright)
# SYNOPSIS
package require Tcl 8\.5
package require pki ?0\.10?
[__::pki::encrypt__ ?*\-binary*? ?*\-hex*? ?*\-pad*? ?*\-nopad*? ?*\-priv*? ?*\-pub*? ?*\-\-*? *input* *key*](#1)
[__::pki::decrypt__ ?*\-binary*? ?*\-hex*? ?*\-unpad*? ?*\-nounpad*? ?*\-priv*? ?*\-pub*? ?*\-\-*? *input* *key*](#2)
[__::pki::sign__ *input* *key* ?*algo*?](#3)
[__::pki::verify__ *signedmessage* *plaintext* *key* ?*algo*?](#4)
[__::pki::key__ *key* ?*password*? ?*encodePem*?](#5)
[__::pki::pkcs::parse\_key__ *key* ?*password*?](#6)
[__::pki::x509::parse\_cert__ *cert*](#7)
[__::pki::rsa::generate__ *bitlength* ?*exponent*?](#8)
[__::pki::x509::verify\_cert__ *cert* *trustedcerts* ?*intermediatecerts*?](#9)
[__::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*?](#10)
[__::pki::pkcs::create\_csr__ *keylist* *namelist* ?*encodePem*? ?*algo*?](#11)
[__::pki::pkcs::parse\_csr__ *csr*](#12)
[__::pki::x509::create\_cert__ *signreqlist* *cakeylist* *serial\_number* *notBefore* *notAfter* *isCA* *extensions* ?*encodePem*? ?*algo*?](#13)
# DESCRIPTION
# COMMANDS
- __::pki::encrypt__ ?*\-binary*? ?*\-hex*? ?*\-pad*? ?*\-nopad*? ?*\-priv*? ?*\-pub*? ?*\-\-*? *input* *key*
Encrypt a message using PKI \(probably RSA\)\.
Requires the caller to specify either __\-priv__ to encrypt with the
private key or __\-pub__ to encrypt with the public key\. The default
option is to pad and return in hex\. One of __\-pub__ or __\-priv__
must be specified\.
The __\-hex__ option causes the data to be returned in encoded as a
hexidecimal string, while the __\-binary__ option causes the data to be
returned as a binary string\. If they are specified multiple times, the last
one specified is used\.
The __\-pad__ option causes the data to be padded per PKCS\#1 prior to
being encrypted\. The __\-nopad__ inhibits this behaviour\. If they are
specified multiple times, the last one specified is used\.
The input to encrypt is specified as *input*\.
The *key* parameter, holding the key to use, is a return value from either
__::pki::pkcs::parse\_key__, __::pki::x509::parse\_cert__, or
__::pki::rsa::generate__\.
Mapping to OpenSSL's __openssl__ application:
1. "openssl rsautl \-encrypt" == "::pki::encrypt \-binary \-pub"
1. "openssl rsautl \-sign" == "::pki::encrypt \-binary \-priv"
- __::pki::decrypt__ ?*\-binary*? ?*\-hex*? ?*\-unpad*? ?*\-nounpad*? ?*\-priv*? ?*\-pub*? ?*\-\-*? *input* *key*
Decrypt a message using PKI \(probably RSA\)\. See __::pki::encrypt__ for
option handling\.
Mapping to OpenSSL's __openssl__ application:
1. "openssl rsautl \-decrypt" == "::pki::decrypt \-binary \-priv"
1. "openssl rsautl \-verify" == "::pki::decrypt \-binary \-pub"
- __::pki::sign__ *input* *key* ?*algo*?
Digitally sign message *input* using the private *key*\.
If *algo* is ommited "sha1" is assumed\. Possible values for *algo*
include "__md5__", "__sha1__", "__sha256__", and "__raw__"\.
Specifying "__raw__" for *algo* will inhibit the building of an ASN\.1
structure to encode which hashing algorithm was chosen\. *Attention*: In
this case the corresponding __pkgi::verify__ must be called __with__
algorithm information\. Conversely, specifying a non\-"__raw__" algorithm
here means that the corresponding __pkgi::verify__ invokation has to be
made *without* algorithm information\.
The *input* should be the plain text, hashing will be performed on it\.
The *key* should include the private key\.
- __::pki::verify__ *signedmessage* *plaintext* *key* ?*algo*?
Verify a digital signature using a public *key*\. Returns true or false\.
*Attention*: The algorithm information *algo* has to be specified if and
only if the __pki::sign__ which generated the *signedmessage* was
called with algorithm "__raw__"\. This inhibited the building of the
ASN\.1 structure encoding the chosen hashing algorithm\. Conversely, if a
proper algorithm was specified during signing then you *must not* specify
an algorithm here\.
- __::pki::key__ *key* ?*password*? ?*encodePem*?
Convert a key structure into a serialized PEM \(default\) or DER encoded
private key suitable for other applications\. For RSA keys this means PKCS\#1\.
- __::pki::pkcs::parse\_key__ *key* ?*password*?
Convert a PKCS\#1 private *key* into a usable key, i\.e\. one which can be
used as argument for __::pki::encrypt__, __::pki::decrypt__,
__::pki::sign__, and __::pki::verify__\.
- __::pki::x509::parse\_cert__ *cert*
Convert an X\.509 certificate to a usable \(public\) key\. The returned
dictionary can be used as argument for __::pki:encrypt__,
__::pki::decrypt__, and __::pki::verify__\. The *cert* argument can
be either PEM or DER encoded\. In addition to the public keying information,
the dictionary contains the following keys containing 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 \(see below\)\.
The dictionary holds additional entries related to keying\. These are
intended for use of the above\-mentioned commands for cryptographic
operations\.
The __extensions__ key in the returned dictionary holds a nested
dictionary whose keys correspond to the names \(with same exact case\) 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\. See the [Examples](\#section3) for an illustration\.
- __::pki::rsa::generate__ *bitlength* ?*exponent*?
Generate a new RSA key pair, the parts of which can be used as argument for
__::pki::encrypt__, __::pki::decrypt__, __::pki::sign__, and
__::pki::verify__\.
The *bitlength* argument is the length of the public key modulus\.
The *exponent* argument should generally not be specified unless you
really know what you are doing\.
- __::pki::x509::verify\_cert__ *cert* *trustedcerts* ?*intermediatecerts*?
Verify that a trust can be found between the certificate specified in the
*cert* argument and one of the certificates specified in the list of
certificates in the *trustedcerts* argument\. \(Eventually the chain can be
through untrusted certificates listed in the *intermediatecerts* argument,
but this is currently unimplemented\)\. The certificates specified in the
*cert* and *trustedcerts* option should be parsed \(from
__::pki::x509::parse\_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*?
Validate that a certificate is valid to be used in some capacity\. If
multiple options are specified they must all be met for this procedure to
return "true"\.
Currently, only the __\-sign\_cert__ option is functional\. Its arguments
are *dn\_to\_be\_signed* and *ca\_depth*\. The *dn\_to\_be\_signed* is the
distinguished from the subject of a certificate to verify that the
certificate specified in the *cert* argument can sign\. The *ca\_depth*
argument is used to indicate at which depth the verification should be done
at\. Some certificates are limited to how far down the chain they can be used
to verify a given certificate\.
- __::pki::pkcs::create\_csr__ *keylist* *namelist* ?*encodePem*? ?*algo*?
Generate 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
encoding as the requested distinguished name in the CSR\.
The *encodePem* option specifies whether or not the result should be PEM
encoded or DER encoded\. A "true" value results in the result being PEM
encoded, while any other value 9results in the the result being DER encoded\.
DER encoding is the default\.
The *algo* argument specifies the hashing algorithm we should use to sign
this certificate signing request with\. The default is "sha1"\. Other possible
values include "md5" and "sha256"\.
- __::pki::pkcs::parse\_csr__ *csr*
Parse a Certificate Signing Request\. The *csr* argument can be either PEM
or DER encoded\. The command returns a dictionary that includes the following
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__ *signreqlist* *cakeylist* *serial\_number* *notBefore* *notAfter* *isCA* *extensions* ?*encodePem*? ?*algo*?
Sign a signing request \(usually from __::pki::pkcs::create\_csr__ or
__::pki::pkcs::parse\_csr__\) with a Certificate Authority \(CA\)
certificate\.
The *signreqlist* argument should be the parsed signing request\.
The *cakeylist* argument should be the parsed CA certificate\.
The *serial\_number* argument should be a serial number unique to this
certificate from this certificate authority\.
The *notBefore* and *notAfter* arguments 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__\)\.
The *isCA* argument is a boolean argument describing whether or not the
signed certificate should be a 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\)\.
The *extensions* argument is 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 any extension\) whether or not the validator should
reject the certificate as invalid if it does not understand the extension
\(if set to "true"\) or should ignore the extension \(if set to "false"\)\. The
*allowCA* argument is used to specify as a boolean value whether or not we
can be used 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 the *caDepth* argument means that this CA cannot sign a
CA certificate and have the result be valid\. A value of "\-1" indicates
infinite depth\.
# EXAMPLES
The example below retrieves a certificate from *www\.example\.com* using the TLS
extension and dumps its content\.
% 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}
# REFERENCES
1. [Internet X\.509 Public Key Infrastructure Certificate and Certificate
Revocation List \(CRL\) Profile](https://www\.rfc\-editor\.org/rfc/rfc5280)
1. [New ASN\.1 Modules for the Public Key Infrastructure Using X\.509
\(PKIX\)](https://www\.rfc\-editor\.org/rfc/rfc5912)
1. [PKCS \#10: Certification Request Syntax
Specification](https://www\.rfc\-editor\.org/rfc/rfc2986)
# AUTHORS
Roy Keene, Ashok P\. Nadkarni
# Bugs, Ideas, Feedback
This document, and the package it describes, will undoubtedly contain bugs and
other problems\. Please report such in the category *rsa* of the [Tcllib
Trackers](http://core\.tcl\.tk/tcllib/reportlist)\. Please also report any ideas
for enhancements you may have for either package and/or documentation\.
When proposing code changes, please provide *unified diffs*, i\.e the output of
__diff \-u__\.
Note further that *attachments* are strongly preferred over inlined patches\.
Attachments can be made by going to the __Edit__ form of the ticket
immediately after its creation, and then using the left\-most button in the
secondary navigation bar\.
# SEE ALSO
[aes\(n\)](\.\./aes/aes\.md), [blowfish\(n\)](\.\./blowfish/blowfish\.md),
[des\(n\)](\.\./des/des\.md), [md5\(n\)](\.\./md5/md5\.md),
[sha1\(n\)](\.\./sha1/sha1\.md)
# KEYWORDS
[cipher](\.\./\.\./\.\./\.\./index\.md\#cipher), [data
integrity](\.\./\.\./\.\./\.\./index\.md\#data\_integrity),
[encryption](\.\./\.\./\.\./\.\./index\.md\#encryption), [public key
cipher](\.\./\.\./\.\./\.\./index\.md\#public\_key\_cipher),
[rsa](\.\./\.\./\.\./\.\./index\.md\#rsa),
[security](\.\./\.\./\.\./\.\./index\.md\#security)
# CATEGORY
Hashes, checksums, and encryption
# COPYRIGHT
Copyright © 2010, 2011, 2012, 2013, 2021 Roy Keene, Andreas Kupries, Ashok P\. Nadkarni