wCME

Version 2.0.1, 23rd March 2019

Copyright © 2017-2019 Mark G. Daniel
This program, comes with ABSOLUTELY NO WARRANTY.
This is free software, and you are welcome to redistribute it under the
conditions of the GNU GENERAL PUBLIC LICENSE, version 3, or any later version.
http://www.gnu.org/licenses/gpl.txt

Contents




wCME  (pronounced "wack-mee")  is a Certificate Management Environment for the Let's Encrypt ™ service.

"The objective of Let's Encrypt and the ACME protocol is to make it possible to set up an HTTPS server and have it automatically obtain a browser-trusted certificate, without any human intervention [and at no cost]. This is accomplished by running a certificate management agent on the web server."

https://www.letsencrypt.org
https://en.wikipedia.org/wiki/Let's_Encrypt

Let's Encrypt is a trademark of the Internet Security Research Group. All rights reserved.

Use of Let's Encrypt requires compliance with the terms and conditions described in the Subscriber Agreement document which can be found at the top the following URL.

https://letsencrypt.org/repository/

wCME is based on a port and adaptation of the BSD, C-language coded, acme-client ACME implementation, and is licensed and distributed with OpenBSD.

https://github.com/openbsd/src/tree/master/usr.sbin/acme-client
Copyright (c) 2016, Kristaps Dzonsons kristaps@bsd.lv
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
https://www.openbsd.org/policy.html

Automatic Certificate Management Environment (ACME) describes a protocol that a certification authority (CA) and an applicant can use to automate the process of verification and certificate issuance. The protocol also provides facilities for other certificate management functions, such as revocation. At the time of writing it is an Internet-Draft and working document of the Internet Engineering Task Force (IETF).

https://ietf-wg-acme.github.io/acme/

The acme-client application is a stable implementation of the ACME protocol, designed to interact with the Let's Encrypt service for the automated issuance, renewal and revocation of server certificates. ACME is a sufficiently complex and demanding protocol that the adoption of an existing application environment was the only effort- and reliability-effective approach to supporting Let's Encrypt with WASD.

wCME uses acme-client to provide the core of the required functionality, with code modifications for use on [Open]VMS, as well as additional code specifically for VMS web server TLS service certificate management. See Implementation.

While wCME is a contraction of WASD Certificate Management Environment, and the application and documentation unreservedly has a WASD emphasis, it is suitable for use with both WASD and VMS Apache. Apache instruction should be carefully evaluated before use and may require some tweaking depending on local requirements.

Apache-specific variation is indicated by a dashed left margin.

wCME v2.0, even with extensive code changes and minor enhancements, is intended to be completely backward compatible with v1.n (with the exception of the original acme-client-portable CLI).

This application is suitable for building with OpenSSL 1.1.n as well as OpenSSL 1.0.2.

This application is not suitable for VAX due to OpenSSL limitation.
VAX servers may still be provided with Let's Encrypt certificates using the https://sslforfree.com service.

How it Operates

When acting as certificate maintenance agent wCME executes within the detached process, "WCME-overseer". Largely quiescent, once a day (at twenty minutes past midnight) it checks certificate expiry and attempts to renew if required. At the time of writing, Let's Encrypt issues certificates with a ninety day lifetime and wCME begins attempting renewal the recommended thirty days in advance of expiry.

Both successful and failed renewal attempts optionally produce an OPCOM message and/or email to configurable targets. Successful renewal optionally executes an action to (re)load the renewed certificate(s) into the server.

wCME generates and maintains two private cryptographic keys. One to identify a unique account with Let's Encrypt and sign HTTP transactions. Another to sign the Certificate Signing Request (CSR) when requesting a certificate, and subsequently to authorise use of that generated certificate by the server (i.e. the traditional private key). wCME supports one account, potentially managing multiple certificates, per system.

Authority to request a certificate is established by the requesting agent demonstrating control over the corresponding service(s). wCME employs the ACME http-01 challenge, where a unique and cryptographically exchanged resource is accesssed by Let's Encrypt using a well-known URI on the standard cleartext service (port 80). Successful access (to each of any multiple resources) satisfies Let's Encrypt and certificate issue proceeds.

The majority of the time the system will show only "WCME-overseer" but the multi-process architecture of acme-client means that when processing a certificate request with Let's Encrypt the system will briefly contain the following processes.

00000F13 WCME-overseer   HIB      5      600   0 00:00:00.27       729    402
00000F14 WCME-main       HIB      5     1445   0 00:00:00.12       337    294  S
00000F15 WCME-netproc    LEF      4     1740   0 00:00:00.64       338    463  S
00000E17 WCME-acctproc   LEF      4     1710   0 00:00:00.60       270    394  S
00000F18 WCME-chngproc   LEF      4      173   0 00:00:00.04       214    290  S
00000F19 WCME-certproc   LEF      4     1704   0 00:00:00.63       230    321  S
00000E1A WCME-fileproc   LEF      4      173   0 00:00:00.05       222    282  S
00000E1B WCME-dnsproc    LEF      5      228   0 00:00:00.08       366    377  S

Usage

wCME supports both WASD and VMS Apache, either as the only Web service on a system, or with both in use on a single system. Where a system supports both server environments wCME can maintain certificates for either or both. Where a cluster supports one or both with cluster-common configurations only a single system should execute wCME to manage the certificates across the cluster. Where a cluster supports one or both without cluster-common configuration each system should execute wCME. The logical names WCME_CERT and WCME_LOAD support multiple values allowing certificate location and action for each to be managed somewhat independently. Note that any generated certificate will be installed in each specified location whether it is in use from that location or not.

Certificates

Certificates remain in the usual location expected by the server and wCME-generated certificates managed independently and then installed in (i.e. copied to) the directory specified by the WCME_CERT logical name. For example:

$ DEFINE /SYSTEM /EXECUTIVE WCME_CERT WASD_ROOT:[LOCAL]
$ DEFINE /SYSTEM /EXECUTIVE WCME_CERT APACHE$ROOT:[CONF.SSL_CRT]

This definition should be added to the startup procedure. In the absence of this logical name generated certificates remain in WCME_ROOT:[SSL].

Certificate files are named using the host name, or first of multiple host names (see below), of the certificate request, made ODS-2 compliant. Let's Encrypt supplies three certificates (the host, the intermediate chain, and the two combined) with the fullchain combined version generally recommended and required to be used by wCME. Using www.example.org for an example:

# WASD_CONFIG_GLOBAL
[SSLcert] WASD_ROOT:[LOCAL]FULLCHAIN_WWW_EXAMPLE_ORG.PEM
or
# WASD_CONFIG_SERVICE
[[https://www.example.org]]
[ServiceSSLcert] WASD_ROOT:[LOCAL]FULLCHAIN_WWW_EXAMPLE_ORG.PEM
# APACHE$COMMON:[CONF]SSL.CONF
SSLCertificateFile /apache$root/conf/ssl_crt/fullchain_www_example_org.pem

wCME automatically appends the private key to the fullchain certificate.

Certificate Load

After wCME renews a certificate it can automatically be loaded into the server(s). The logical name WCME_LOAD defines an action performed to accomplish this. In the absence of this logical name the certificate load must be performed manually.

Multiple Hosts

Let's Encrypt  ACME version 1 server (the wCME implementation) does not support wildcard certificates* but will issue a certificate for multiple hosts (at time of writing, up to one hundred) by using altnames. This means that a single certificate may be used and managed for multiple, or even all, services of a site. However, each one will be individually challenged and so must have an associated cleartext service and be accessible from the Internet (see configuration item 4).

* ACME version 2 has been implemented:
https://letsencrypt.org/docs/acme-protocol-updates/
  wCME (via acme-client) does not (currently) support version 2

Command-Line

Command-line usage is via a foreign verb or MCR.

$ wcme == "$cgi_exe:wcme"
$ mcr cgi_exe:wcme
$ wcme == "$apache$common:[cgi-bin]wcme"
$ mcr apache$common:[cgi-bin]wcme

wCME requires possssion of SYSPRV for command-line use.

Account Registration

An account must be registered with Let's Encrypt before wCME can be used for certification. Two private cryptographic keys are created to identify the end-user to the CA and sign data exchanged with the service. This is performed manually at the command-line.

$ wcme /register

Generally only required the once, it can be done again at any time to (re)create an(other unique) account. If this happens an initial certification must also be redone for all managed services.

Initial Certification

Before wCME can be used for maintenance an initial certification must be made. This is performed manually at the command-line. It is also necessary when the number or composition of services changes. Failure to maintain the currency of a certificate will likely result in failure at next automated renewal. Multiple host names must be comma-separated.

$ wcme /certify=www.example.org

Once a certificate or certificates are successfully generated they need to be loaded into the running server. For WASD v11.1.0 or later this may be performed using

$ httpd /do=ssl=cert=load
or for earlier releases
$ httpd /do=restart[=now]

When in detached operation wCME automatically can perform this function. See point 6 in Configuration.

If a non-trivial number of services are to be certified it is suggested that a command procedure be created in WCME_ROOT:[ETC] that contains the necessary command. The can then be edited and executed as required. For example:

$! CERTIFY_EXAMPLE_SERVICES.COM
$ wcme = "$cgi_exe:wcme"
$ wcme /certify=www.example.org,two.example.org,three.example.org,-
four.example.org,five.example.org,six.example.org,seven.example.org,-
eight.example.org,nine.example.org,ten.example.org

Note that Let's Encrypt has limits on the number of certifications in a given period.

https://letsencrypt.org/docs/rate-limits/

Other Functions

Functions available from the VMS command-line.

Command-Line Description
/certify=host(s) Request Let's Encrypt to issue a certificate that includes the specified host or comma-separated list of hosts.
/check=ca Test that the CA is accessible by performing a directory query with it.
/check=mail Test the WCME_MAIL logical name reporting target.
/check=opcom Test the WCME_OPCOM logical name reporting target.
/check=load Test the WCME_LOAD logical name certificate (re)load.
/list List the certificates currently being managed.
/manage Manually run the certificate management function normally executed once a day by the overseer process.
/version Display the executable version.

Installation

Requires a minimum VMS V7.1 and if compiling, OpenSSL 1.1.n or 1.0.2.

Basic steps:

  1. obtain kit(s)
  2. unzip kit(s)
  3. build application
  4. copy executable
  5. configure
  6. application startup
  7. certification
  8. server restart

Expanded descriptions:

  1. Obtain the kit(s) from
    https://wasd.vsm.com.au/wasd/
  2. The source, and optionally object modules, should be UNZIPed.
    $ SET DEFAULT WASD_ROOT:[000000]
    $ UNZIP <location>:WCMEnnn.ZIP
    $ UNZIP <location>:WCMEnnn-<platform>.ZIP
    $ SET DEFAULT [SRC.WCME]
    
    $ SET DEFAULT APACHE$COMMON:[000000]
    $ UNZIP <location>:WCMEnnn.ZIP
    $ UNZIP <location>:WCMEnnn-<platform>.ZIP
    $ SET DEFAULT [SRC.WCME]
    
  3. A build requires two parameters.
    $ @BUILD_WCME <p1> <p2>
    
    Parameter Purpose Description
    P1 build mode BUILD (compile then link), COMPILE or LINK
    P2 SSL package root Directory specification of SSL package. Examples:
    WASD_ROOT:[SRC.OPENSSL-1_1_1A]
    WASD_ROOT:[SRC.OPENSSL-1_0_2Q]
    SYS$COMMON:[OPENSSL]
    SYS$COMMON:[SSL1]
    For example:
    $ @BUILD_WCME BUILD WASD_ROOT:[SRC.OPENSSL-1_1_1A]
    

  4. Copy the application executable to the script location.
    $ COPY [.OBJ_<platform>]WCME.EXE CGI_EXE:
    
    $ COPY [.OBJ_<platform>]WCME.EXE APACHE$COMMON:[CGI-BIN]
    

  5. Configure the application.

  6. The WCME_STARTUP.COM procedure will accept DCL symbols representing the runtime logical names and these may be used to customise the site startup. For example:
    $ WCME_CERT = "WASD_ROOT:[LOCAL]"
    $ WCME_LOAD = "@WASD_ROOT:[SRC.WCME]WCME_LOAD"
    $ WCME_MAIL = "SYSTEM,mark.daniel@wasd.vsm.com.au"
    $ WCME_OPCOM = "CENTRAL,NETWORK"
    $ @WASD_ROOT:[SRC.WCME]WCME_STARTUP.COM SYSTEM WASD
    

    Execute the wCME startup procedure. For example:

    $ @WASD_ROOT:[SRC.WCME]WCME_STARTUP.COM SYSTEM WASD
    

    Ensure the startup procedure and parameters are edited into the system startup.

  7. Request the initial certificate as described in Account Registration and Initial Certification above.

  8. When successfully certified restart the server to use the fresh Let's Encrypt certificate(s).

Update

Configuration

All logical names must be defined in the SYSTEM table.**

Basic steps:

  1. choose an account for the agent
  2. create application directory structure
  3. copy the CA certificate bundle
  4. responding to the challenge
  5. service certificate specification
  6. certificate load logical name
  7. reporting logical names
  8. authorisation for admin URIs

**WCME_STARTUP.COM can assist with this.

Expanded descriptions:

  1. Decide on which account will be used to execute the detached overseer process. The account requires read and execute access to the WCME_STARTUP.COM procedure and the WCME.EXE executable locations. An explicitly privileged account is not required. The executable is INSTALLed with required additional privilege and establishes baseline privilege at NETMBX and TMPMBX then adds SYSPRV when needing access to the file system (certificate, challenge and log files). The WASD scripting account (default HTTP$NOBODY) is a natural candidate. SYSTEM may also be used (and is shown used in all the examples).

  2. A concealed-device logical name is required to locate the working directories.***
    $ DEFINE /SYSTEM /TRANS=CONCEALED /EXECUTIVE WCME_ROOT -
             $1$DKA0:[WASD_ROOT.LOCAL.WCME.]
    
    $ DEFINE /SYSTEM /TRANS=CONCEALED /EXECUTIVE WCME_ROOT -
             $1$DKA0:[SYS0.SYSCOMMON.APACHE.WCME.]
    

    This definition should be added to the server startup procedures prior to starting the application.**

    Then the required directory structure must be created.***

    $ CREATE /DIRECTORY WCME_ROOT:[ETC]
    $ CREATE /DIRECTORY WCME_ROOT:[LOG]
    $ CREATE /DIRECTORY WCME_ROOT:[PRIV]
    $ CREATE /DIRECTORY WCME_ROOT:[SSL]
    $ CREATE /DIRECTORY WCME_ROOT:[WWW]
    
    ***WCME_SETUP.COM will perform these steps.

  3. Copy the Certificate Authority bundle into the wCME directory structure.
    $ COPY CACERT-release.PEM WCME_ROOT:[ETC]CACERT.PEM
    

    The CA bundle is used by wCME to verify the authenticity of the Let's Encrypt service used to issue the server certificate.

    The bundle will generally be up-to-date with new releases of wCME and also may be refreshed at any time using any reliable source. The cURL project provides such a resource. This is generated from the root certificates used by the Mozilla Foundation for its Firefox product (and others).

    https://curl.haxx.se/docs/caextract.html
  4. The ACME http-01 challenge used by wCME must be provided by either existing cleartext service(s) on the system, or by enabling the wCME standalone http-01 challenge server.

    Be sure to test challenge processing using:

    for all services to be certified, with each providing a response something like:

    Challenge received but no such file or directory.
    

    The challenge received is the important positive indicator.
    Anything else requires investigation and correction.
    (The no such file or directory is just the absence of a real Let's Encrypt challenge.)

  5. Services must use the wCME certificate naming convention. For example:
    # WASD_CONFIG_SERVICE
    [[https://www.example.org]]
    [ServiceSSLcert] WASD_ROOT:[LOCAL]FULLCHAIN_WWW_EXAMPLE_ORG.PEM
    
    or
    # WASD_CONFIG_GLOBAL
    [SSLcert] WASD_ROOT:[LOCAL]FULLCHAIN_WWW_EXAMPLE_ORG.PEM
    
    # APACHE$COMMON:[CONF]SSL.CONF
    SSLCertificateFile /apache$root/conf/ssl_crt/fullchain_www_example_org.pem
    

    The logical name WCME_CERT locates the server configuration directory containing the certificate(s).** For example:

    $ DEFINE /SYSTEM /EXECUTIVE WCME_CERT WASD_ROOT:[LOCAL]
    

    The logical name may define multiple values in which case the certificate is installed (i.e. copied to) multiple locations (e.g. WASD and Apache).

    $ DEFINE /SYSTEM /EXECUTIVE WCME_CERT WASD_ROOT:[LOCAL],APACHE$ROOT:[CONF.SSL_CRT]
    
  6. Successfully renewed certificates may automatically be loaded into the server by defining the logical name WCME_LOAD containing an action to perform.** A subprocess is spawned to execute the action. The subprocess has SYSPRV and IMPERSONATE (for Apache) authorised. The action can be any DCL but commonly execution of a procedure. The WCME_LOAD.COM procedure provides a certificate reload (i.e. not a restart) for WASD v11.1.0 and later, a server restart for earlier versions, and an Apache restart, based on the environment. Evaluate suitability before use.
    $ DEFINE /SYSTEM /EXECUTIVE WCME_LOAD "@WASD_ROOT:[SRC.WCME]WCME_LOAD.COM"
    

    If the logical name does not exist the certificate load must be performed manually. The logical name may define multiple values in which case the certificate load is executed multiple times (e.g. for WASD and Apache).

  7. Successful and unsuccessful attempts to renew certificates are logged, and optionally also reported via MAIL and OPCOM. The MAIL and OPCOM targets are both configured using logical names.** Each can contain multiple, comma-separated targets, with a MAIL target anything that can be addressed at the command-line. By default OPCOM reports to CENTRAL and may be disabled completely by defining the logical name as NONE. These should be added to the startup procedure. For example.
    $ DEFINE /SYSTEM /EXECUTIVE WCME_MAIL "system,smtp%""whomever@wherever"""
    $ DEFINE /SYSTEM /EXECUTIVE WCME_OPCOM "central,software,oper2"
    
  8. The application (script) can be accessed using a browser for administrative purposes.
    URI Description
    /cgi-bin/wcme/admin/list Reports on the current certificate(s) being managed.
    /cgi-bin/wcme/admin/log Reports the current overseer log.
    /cgi-bin/wcme/admin/check/ca Test that the CA is accessible by performing a directory.
    /cgi-bin/wcme/admin/check/load Test WCME_LOAD logical name by performing the action. Caution: may restart server(s) or the like!
    /cgi-bin/wcme/admin/check/mail Test WCME_MAIL logical name by sending a test message.
    /cgi-bin/wcme/admin/check/opcom Test WCME_OPCOM logical name by sending a test message.

    The admin path (only) must be subject to authorisation. For example:

    # WASD_CONFIG_AUTH
    ["VMS credentials"=WASD_VMS_RW=id]
    /httpd/-/admin/* r+w,https:
    /cgi-bin/wcme/admin/* read,https:
    
    <Location /cgi-bin/wcme/admin>
    AuthType Basic
    AuthName "OpenVMS authentication"
    AuthUserOpenVMS On
    require valid-user
    </Location>
    

Implementation

wCME uses the PIPE DCL command and requires a minimum of VMS V7.1.

wCME is based on a port of the OpenBSD acme-client ACME implementation. This is an adaptation of an original application with the same name by Kristaps Dzonsons, a variant of which version 1 of wCME was adapted from. This has been moved into the OpenBSD baseline and the original is no longer maintained. To be able to remain current wCME needed to follow, resulting in version 2.

The port required an adaptation of C-language code to operate with VMS, DECC compiler and the post-VMS-v7.0 C-RTL, as well as BSD-style Unix assumptions regarding the file-system and like. The acme-client application uses several independent processes communicating via a Unix socket IPC to partition functional activity, along with sandbox/jail behaviour to enable and constrain file-system access. wCME enables and controls file-system access to otherwise protected resources by enabling/disabling SYSPRV access within C-RTL file-system wrapper functions. Conditional compilation has general VMS adaptations using #if[n]def __VMS while wCME-specific code uses #if[n]def WCME_IDIOM.

wCME approaches the task of supporting both WASD and VMS Apache by avoiding the specifics of each, operating in an independent directory structure and allowing the sysadmin to direct the certificate products and server actions using logical names.

As WASD is designed to allow and known to be installed on ODS-2 volumes, wCME file-system elements are explicitly constrained to ODS-2 syntax. Apache comes along for the ride. This means alphanumerics, underscores and hyphens in directory and file names, 39+39 character names, with multiple periods converted to underscores, etc. ODS-2 compliance is a significant element of the WCME_IDIOM.

wCME also includes a fit-for-purpose port of the LibreSSL TLS library code, interfaced as best it can be to mainstream OpenSSL. LibTLS is a significant dependency of acme-client. This should NOT be considered a thorough and general-purpose port. LibreSSL is licensed under the same conditions as OpenSSL.

https://github.com/libressl-portable/openbsd/tree/master/src/lib/libtls
The OpenSSL toolkit stays under a dual license, i.e. both the conditions of
the OpenSSL License and the original SSLeay license apply to the toolkit.
See below for the actual license texts. Actually both licenses are BSD-style
Open Source licenses. In case of any license issues related to OpenSSL
please contact openssl-core@openssl.org.
https://github.com/libressl/libressl/blob/master/src/LICENSE

Problems?

Releases

v2.0.1  23-MAR-2019
•  detect and act on process name change failure
•  OpenBSD acme-client as at 20-MAR-2019
v2.0.0  30-JAN-2019
•  move from acme-client-portable to OpenBSD acme-client
•  OpenBSD acme-client as at 18-DEC-2018
•  LibreSSL LIBTLS as at 18-DEC-2018
•  support OpenSSL 1.1.n (1.1.1) as well as 1.0.2
v1.3.0  31-MAR-2018
•  logical name WCME_AGREEMENT and associated functionality (obsolete in v2.0.0)
v1.2.0  15-OCT-2017
•  pairofsockets() substitutes socketpair() for building on earlier than VMS V8.2
v1.1.0  30-JUL-2017
•  standalone http-01 challenge server
v1.0.0  09-JUL-2017
•  initial

References

A few URLs of interest and example.

Acknowlegements

Many thanks to Kristaps Dzonsons for making the original acme-client-portable freely available.