{"id":22302612,"url":"https://github.com/dataoneorg/ca","last_synced_at":"2025-10-14T00:30:45.632Z","repository":{"id":74058337,"uuid":"591528317","full_name":"DataONEorg/ca","owner":"DataONEorg","description":"DataONE Certificate Authority","archived":false,"fork":false,"pushed_at":"2025-01-20T03:20:10.000Z","size":3268,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-01-22T15:48:41.709Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/DataONEorg.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2023-01-21T01:33:44.000Z","updated_at":"2025-01-20T03:20:11.000Z","dependencies_parsed_at":null,"dependency_job_id":"b1d3c22c-66bd-440c-b2b5-332a1dda84a6","html_url":"https://github.com/DataONEorg/ca","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DataONEorg%2Fca","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DataONEorg%2Fca/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DataONEorg%2Fca/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DataONEorg%2Fca/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/DataONEorg","download_url":"https://codeload.github.com/DataONEorg/ca/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":236422784,"owners_count":19146323,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-03T18:40:01.588Z","updated_at":"2025-10-14T00:30:40.010Z","avatar_url":"https://github.com/DataONEorg.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# DataONE Certificate Authority\n\n**Also see the [DataONE Certificate Creation - Quick Reference Guide](./CertCreationQuickRef.md)**\n\n\n## Current cert status:\n\nThis spreadsheet is updated weekly by [a GitHub Action](https://github.com/DataONEorg/ca/blob/main/.github/workflows/check_cert_status.yml)\n\n* [Production certs](https://flatgithub.com/DataONEorg/ca?filename=prod_cert_status.csv)\n\n## Overview\n\nThis directory contains configuration files and notes on how to set up the\nDataONE Certificate Authority using [OpenSSL](https://www.openssl.org) as the\nCA application. OpenSSL generates all files needed for the CA, including\ncertificate requests, keys, certificates, and certificate revocation lists.\n\nThe DataONE Certificate Authority is governed by a Root CA, which delegates\nall certificate signing and management to a Production CA. The private key\nfor the Root CA is offline and completely protected, which protects the CA\nshould somehow the Production CA private key be compromised. This document\nshows the steps used to create both the Root CA and the Production CA, as well\nas to perform common options such as creation and revocation of certificates\nwith the Production CA. The operations have been encapsulated in the `ca`\nshell script.\n\nThere is also a Test CA, used for generating certificates for servers in the\ndev, staging, and sandbox environments, but this CA is completely independent\nof the Production CA and its certificates will not be accepted in the\nproduction environments. The Test CA has the same hierarchy as the Production\nCA, with a Root CA delegating certificate signing and management to an\nintermediate CA.\n\n\n## Key Security\n\nNew certificates created using the CA have two components: the **certificate** and\nthe **private key**:\n* The certificate can be publicly exposed, and should be added to GitHub\nand checked in. \n* Keys MUST be kept private. After the certificate and private key\nare provided to the Node administrator (see `publish_cert_orcid` in the\n[\"Use\" section](#use), below), any local copies of the private key should be\ndeleted. (We no longer keep copies of these Node keys, since a\nnew cert and key can be generated easily if a key is lost or compromised.)\n\nThe private keys needed to issue certs are contained in a binary sparsebundle file. Contact\nDataONE root system administrators for access.\n\n\u003e #### VERY IMPORTANT! Since merge commits are not possible with a binary file, ALWAYS...\n\u003e 1) Pull the latest version of the sparsebundle before starting any changes.\n\u003e 2) Inform other certificate admins on slack that you are working in the bundle.\n\u003e 3) Push your sparsebundle changes **immediately**, and inform the other admins when you're done.\n\n\n## Requirements\n\nThe CA scripts rely on the BASH shell and are developed on OS X (bash 3.2.53)\nthough should work without modification on Linux. Dependencies are:\n\n- [OpenSSL](https://www.openssl.org)\n- Standard command line tools such as `sed`, `awk`, `cut`, `sort`, `git`\n\n\n## Installation\n\nInstalling the DataONE CA involves the following steps. In these instructions,\nit is assumed that the CA software is being installed in\n`${HOME}/Projects/DataONE/tools`, identified by `${CA_HOME}` in the examples.\nAdjust as appropriate for your system.\n\n1. The CA is distributed from GitHub. Checkout the tool to the desired\n   location\n\n    ```shell\n      cd ${HOME}/Projects/DataONE/tools\n      git clone git@github.com:DataONEorg/ca.git\n      export CA_HOME=\"$(pwd)/ca\"\n    ```\n\n2. Create a symbolic link for `/var/ca` to the checkout location:\n\n    ```shell\n      sudo ln -s ${CA_HOME}/ca /var/ca\n    ```\n\n3. Mount the encrypted volume using Finder or the command line when ready to\n   create certificates or update the revocation list:\n\n    ```shell\n      hdiutil attach -agentpass /path/to/encrypted/DMG\n    ```\n\n\u003e **Note** --\n\u003e    Do not keep the encrypted volume with the keys on your laptop or any\n\u003e    other device that is regularly connected to the Internet. Keep it on a\n\u003e    USB stick or some other physical media that can be disconnected.\n\nVerify the installation by running the `cert_status` script:\n\n```shell\n  cd ${CA_HOME}\n  ./cert_status\n```\n\nIf all is good, then the script will examine the contents of the Test\nEnvironment certificates folder and report on the status of each .pem file\nfound there. The output is lengthy, and looks something like:\n\n```shell\n  {\"what\":\"Certificate Status\",\n   \"Generated\":\"2015-03-18T11:23:26.000+00:00\",\n   \"content\":[\n  {\n   \"File_name\"   : \"/Users/vieglais/Projects/DataONE_61385/svn/software/tools/trunk/ca/DataONETestIntCA/certs/cn-dev-orc-1.pem\",\n   \"Author\"      : \"\",\n   \"Serial\"      : \"DA3263A2A12D004B\",\n   \"DN\"          : \"DC=org,DC=dataone,DC=test,CN=cn-dev-orc-1\",\n   \"Created\"     : \"2012-07-24T03:39:45.000+00:00\",\n   \"Expires\"     : \"2015-07-24T03:39:45.000+00:00\",\n   \"Expires_days\": 127,\n   \"Revocation\"  : \"Revoked\",\n   \"Validity\"    : \"Valid\"\n  }\n  ,\n  {\n   \"File_name\"   : \"/Users/vieglais/Projects/DataONE_61385/svn/software/tools/trunk/ca/DataONETestIntCA/certs/cn-dev-orc-1.test.dataone.org-1.pem\",\n   \"Author\"      : \"\",\n   \"Serial\"      : \"DA3263A2A12D0055\",\n   \"DN\"          : \"DC=org,DC=dataone,CN=cn-dev-orc-1.test.dataone.org\",\n   \"Created\"     : \"2012-07-27T21:25:34.000+00:00\",\n   \"Expires\"     : \"2015-07-27T21:25:34.000+00:00\",\n   \"Expires_days\": 131,\n   \"Revocation\"  : \"Revoked\",\n   \"Validity\"    : \"Valid\"\n  }\n  ...\n```\n\nand so on.\n\n\n## Use\n\nFour shell scripts are included to assist with certificate management:\n\n`ca`: This is the main script for creating and revoking certificates.\n\n`cert_status`: This script reports the status for a single certificate or all certificates\nin an environment.\n\n`publish_cert` and `publish_cert_orcid`: Provide a convenient mechanism for packaging a certificate\nand key, and placing them in a secure location for download by an authenticated user.\n\nThe `publish_crl` script (for publishing the certificate revocation list to the CRL servers) has\nbeen move to the `SHA-1_ARCHIVE` directory. In practice no clients rely on the CRL -- see\n[this blog post](https://scotthelme.co.uk/revocation-is-broken/) for more explanation. If you still\nneed details of how to use the `publish_crl` script, see the\n[original README file](https://github.com/DataONEorg/ca/blob/8084ba68af07fda0ed926764a4dd1a5d479060e7/README.rst?plain=1#L293)\n\n\n### `ca`\n\nThe shell program `ca` can be used to manage certificates from both the Test\nCA and the Production CA. It determines which CA to use based on commandline\narguments. Type `./ca -h` to see the usage help for the `ca` utility.\n\nTo install the DataONE certificate authority, simply:\n\n1) install openssl on your machine\n\n2) Check out a working copy of the CA from the DataONE GitHub repository\n\n3) Mount the private key encrypted volume under /Volumes/DataONE\n\nThe `ca` utility can create, revoke, and display certificates, and can\ngenerate the Certificate Revocation List (CRL) for either of the CAs. Examples\nfollow:\n\nTo create a Production certificate for the MN with nodeid \"KNB\":\n\n```shell\n  ./ca -c Prod urn:node:KNB\n```\n\nTo display a Production certificate for the MN with nodeid \"KNB\":\n\n```shell\n  ./ca -d Prod urn:node:KNB\n```\n\nTo revoke a Production certificate for the MN with nodeid \"KNB\":\n\n```shell\n  ./ca -r Prod urn:node:KNB\n```\n\nTo generate a CRL for the Prod CA:\n\n```shell\n  ./ca -g Prod\n```\n\nAny of these commands can be made to work on the Test CA instead by switching\n`Prod` to `Test`.\n\nOnce new CSRs, Certificates, and CRLs have been generated, they should be\nadded to GitHub and all modified files should be checked in to GitHub so that others\nmanaging the  CA can access all the updated content. The only exception are\nthe private keys that are generated, which should be given to the MN operator\nalong with instructions on how to protect the private key. The private key\nshould be deleted from the CA to avoid possible exposure of the keys.\n\n\n### `cert_status`\n\nThe script `cert_status` provides a mechanism to report on the status of a\nsingle certificate or all certificates within the Production or Test\nenvironments. Report output is in JSON or pipe (|) separated values and\nincludes the attributes:\n\n* `File_name`: Full path to the certificate\n* `Author`: The name of the GitHub user that checked in the certificate\n* `Serial`: The certificate serial number\n* `DN`: The certificate Distinguished Name\n* `Created`: Indicates when the certificate was created\n* `Expires`: Indicates when the certificate will expire\n* `Expires_days`: Number of days until the expiration date\n* `Revocation`: Indicates if the certificate appears in the revocation list\n* `Validity`: Indicates if the test `openssl verify` passes.\n\n`cert_status` can also be used to generate VCalendar .ics files, one for\nProduction and one for the Test environment, that includes dates for\ncertificate and revocation list expiry. These are checked in to GitHub\nand can be subscribed to using Google Calendar or iCal using the calendar\nlocations of:\n\nhttps://raw.githubusercontent.com/DataONEorg/ca/main/Prod_events.ics\n\nfor the Production environment, and:\n\nhttps://raw.githubusercontent.com/DataONEorg/ca/main/Test_events.ics\n\nfor the Test environment.\n\n**Example** Show status of a single certificate in test environment:\n\n```shell\n  ./ca cert_status -A DataONETestIntCA/certs/urn\\:node\\:mnTestGulfWatch.pem\n```\n\n**Example** Show status of a single certificate in production environment,\nusing the default locations for certificates and CRL:\n\n```shell\n  ./cert_status -A -P DataONEProdIntCA/certs/urn\\:node\\:GULFWATCH.pem\n```\n\n**Example** Show status of a single certificate in production environment,\nexplicitly indicating which certificates and CRL to use:\n\n```shell\n  ./cert_status -A \\\n    -a DataONEProdIntCA/certs/DataONEProdIntCA.pem \\\n    -c DataONEProdRootCA/certs/DataONEProdRootCA.pem \\\n    DataONEProdIntCA/certs/urn\\:node\\:GULFWATCH.pem\n```\n\n**Example** Generate a pipe delimited text file reporting on all the\ntest certificates:\n\n```shell\n  ./cert_status -S \u003e testcerts.csv; \\\n  for f in $(find DataONETestIntCA/certs -name *.pem); \\\n    do ./cert_status -A -s $f \u003e\u003e testcerts.csv; done\n ```\n\nor:\n\n```shell\n   ./cert_status -s -A DataONETestIntCA/certs\n```\n\n**Example** Generate a pipe delimited text file reporting on all the\nproduction certificates:\n\n```shell\n  ./cert_status -H \u003e testcerts.csv; \\\n  for f in $(find DataONETestIntCA/certs -name *.pem); \\\n  do ./cert_status -A -s \\\n   -a DataONEProdIntCA/certs/DataONEProdIntCA.pem \\\n   -c DataONEProdRootCA/certs/DataONEProdRootCA.pem \\\n  $f \u003e\u003e prodcerts.csv; done\n```\n\nor:\n\n```shell\n  ./ca cert_status -s -A -P DataONEProdIntCA/certs\n```\n\n**Example** Generate a calendar of events in .ics format for production\nenvironment certificate expirations and the next update time for the  CRL.\nOutput is to the file \"Prod_events.ics\" for the production  environment or\n\"Test_events.ics\" for the test environment. The  calendar can be subscribed to\nusing the respective GitHub URL:\n\n```shell\n  ./ca cert_status -P -L\n```\n\n### `publish_cert` and `publish_cert_orcid`\n\nThe scripts `publish_cert` and `publish_cert_orcid` each provide a convenient mechanism to\npackage a certificate, its key, and the CSR used to generate the certificate into a .zip\nfile and upload it to the distribution server (currently https://project.dataone.org/).\n\nThe script accepts two arguments:\n1. the ID of the user who will retrieve the package. this will be:\n   * the user's LDAP uid, when using `publish_cert`, or\n   * the user's ORCID, when using `publish_cert_orcid` (but only the numerical part; see below).\n2. the path to the certificate. The certificate is expected to be located in the `certs`\n   folder of the respective CA.\n\n\u003e **Note** -- The resulting file names have the \":\" character replaced with \"_\".\n\nThe script uses ssh to connect to the distribution host, create a target\nfolder if necessary, and upload the package .zip file. As such, it is\nnecessary for the user running the script to have SSH access to the\ndistribution host and write access to the destination folder (`/var/www/users`).\n\n**Example** Share a certificate and key for user vieglais:\n\n```shell\n  # For LDAP:\n  ./ca publish_cert vieglais DataONETestIntCA/certs/urn:node:ATestCert.pem\n  \n  # or for ORCID:\n  ./ca publish_cert 0000-0002-6513-4996 DataONETestIntCA/certs/urn:node:ATestCert.pem\n```\n\u003e **Note** -- Only the numerical part of the ORCID should be used, as shown in the example above!\n\nThe resulting package would be downloadable from:\n\nhttps://project.dataone.org/~vieglais/urn_node_ATestCert.zip\n\nAfter unzipping, the result would be:\n\n```shell\n  urn_node_ATestCert/\n    info.txt\n    urn_node_ATestCert.pem\n    urn_node_ATestCert.csr\n    private/\n      urn_node_ATestCert.key\n```\n\nThe file `info.txt` contains general information about the certificate\ngenerated by the `cert_status` program.\n\n\n## Appendix 1: Additional notes on OpenSSL setup and usage\n\nOpenSSL was used to create the various CA files and operate the CA. The\nfollowing sections are a synopsis of how all the CAs were created and how\nvarious CA functions can be run using OpenSSL alone.  The `ca` shell script\nautomates some of these functions (most notably for Node certificate creation),\nso their inclusion here is mainly as a reference and not intended for typical usage.\n\nFor more information on OpenSSL, see [openssl.org](https://www.openssl.org). For more detail\non the configuration files (`openssl.cnf` or `openssl.tmpl`), see\n[the openssl documentation](https://www.openssl.org/docs/man1.1.1/man5/config.html)\nor [this Openssl.conf walkthrough](https://www.phildev.net/ssl/opensslconf.html)\n\n\n### SHA-256 Updates, Cross-Signing, and Naming Scheme\n\nThe original CA certificates were generated using SHA-1, which is now considered insecure. In 2024,\ntherefore, new SHA-256-encrypted Root CAs were generated, and these were used to \"cross-sign\"\nthe intermediate certs. This process entailed generating new Intermediate CA certs for\nProduction and Test, while ensuring:\n\n1. they had the same Subject/DN as the old intermediate certs, and\n2. they were signed with the original private keys that were used to sign the old intermediate\n   certs.\n\nSee [Appendix 2](#appendix-2-certificate-cross-signing) for a brief overview of how Cross Signing works\n\nAt the same time, all the old SHA-1 contents of this repo were moved into the `SHA-1_ARCHIVE`\nsubdirectory (see [Appendix 3](#appendix-3-directory-structure)). A new, clearer and more-consistent\nnaming convention was then adopted for the new directories and files, as follows:\n\n```shell\n                          PRODUCTION                         TEST\n-----------------------------------------------------------------------------------\n### ROOT ###\ndirectory name:         DataONEProdRootCA             DataONETestRootCA\n     cert name:         DataONEProdRootCA.pem         DataONETestRootCA.pem\n           CN =        \"DataONE Prod Root CA\"        \"DataONE Test Root CA\"\n\n### INTERMEDIATE ###\ndirectory name:         DataONEProdIntCA              DataONETestIntCA\n     cert name:         DataONEProdIntCA.pem          DataONETestIntCA.pem\n(see Note) CN =        \"DataONE Production CA\"       \"DataONE Test Intermediate CA\"\n```\n\n**NOTE:** The Intermediate CNs are inconsistent because the Subjects (and therefore the CN\nvalues) for the Intermediate certs must match those in the old SHA-1 root CAs, in order for\ncross-signing to work.\n\nIf we have the opportunity to change the Intermediate CNs in the future, we can make them consistent\nby renaming `\"DataONE Production CA\"` to `\"DataONE Prod Intermediate CA\"`.\n\n### Certificate Details\n\n#### CA DN formats\n\n```shell\n  # Production\n  DC=org, DC=dataone, CN=DataONE Prod Root CA\n  DC=org, DC=dataone, CN=DataONE Production CA\n\n  #Test\n  DC=org, DC=dataone, CN=DataONE Test Root CA\n  DC=org, DC=dataone, CN=DataONE Test Intermediate CA\n```\n\n#### Node DN formats\n\n```shell\n  DC=org, DC=dataone, CN=urn:node:SOMENODE\n```\n\n#### CA Certificate validity\n\n```shell\n  100 years\n```\n\n#### Node Certificate validity\n\n```shell\n  3 years\n```\n\n### Creating the Production Root CA\n\n```shell\n  mkdir /var/ca\n  cd /var/ca\n  mkdir DataONEProdRootCA\n  cd DataONEProdRootCA\n  mkdir certs newcerts private req\n  touch index.txt\n  # Edit the openssl.cnf config file if needed; e.g. check the 'dir' entry in [ CA_default ].\n\n  openssl req -new -newkey rsa:4096 -keyout /Volumes/DataONE/DataONEProdRootCA.key \\\n    -out req/DataONEProdRootCA.csr -config ./openssl.cnf\n\n  # You will be prompted for:\n  # 1. a passphrase to set for the new key, and\n  # 2. the Common Name (CN) to set\n\n  openssl ca -create_serial -out certs/DataONEProdRootCA.pem -days 36500 \\\n    -keyfile /Volumes/DataONE/DataONEProdRootCA.key -selfsign -config ./openssl.cnf \\\n    -extensions v3_ca -infiles req/DataONEProdRootCA.csr\n\n    # You will be prompted for the passphrase for the existing (prod root) key\n```\n\n### Creating the Production Intermediate CA\n\n```shell\n  cd ..\n  mkdir DataONEProdIntCA\n  cd DataONEProdIntCA\n  mkdir certs newcerts private req\n  touch index.txt\n  # No need to edit the config file; uses the one from the root CA\n\n   ###\n  # This is how we did it originally:\n  # ### OMIT FOR CROSS SIGNING ###\n      # openssl req -new -newkey rsa:4096 -keyout /Volumes/DataONE/DataONEProdCA.key \\\n      #   -out req/DataONEProdIntCA.csr -config ../DataONEProdRootCA/openssl.cnf\n\n      # # You will be prompted for:\n      # # 1. the Common Name (CN) to set, and\n      # # 2. a passphrase to set for the new key\n  # ### END OMIT FOR CROSS SIGNING ###\n  #\n  # However, for cross-signing, we should NOT generate a new key (\" -newkey \"),\n  # but instead re-use the original intermediate key...\n  ###\n  openssl req -new -key /Volumes/DataONE/SHA-1_ARCHIVE/DataONEProdCA.key \\\n    -out req/DataONEProdIntCA.csr -config ../DataONEProdRootCA/openssl.cnf\n\n  # You will be prompted for:\n  # 1. the passphrase for the existing (prod intermediate) key, and\n  # 2. the Common Name (CN) to set (NOTE for cross-signing, this MUST match the CN used in the old\n  #    intermediate cert!)\n\n  cd ../DataONEProdRootCA\n\n  openssl ca -out ../DataONEProdIntCA/certs/DataONEProdIntCA.pem -days 36500 \\\n    -keyfile /Volumes/DataONE/DataONEProdRootCA.key -config ./openssl.cnf \\\n    -extensions v3_ca -infiles ../DataONEProdIntCA/req/DataONEProdIntCA.csr\n\n  # You will be prompted for the passphrase for the existing (prod root) key\n```\n\n### Creating the Certificate Chain File\n\n```shell\n  cd ..\n\n  cat DataONEProdRootCA/certs/DataONEProdRootCA.pem \\\n    DataONEProdIntCA/certs/DataONEProdIntCA.pem \u003e DataONECAChain.crt\n\n    # ...and similarly for Test certs\n```\n\n\u003e NOTE - in addition to the DataONE Root and Intermediate CA certs, the Prod and Test CA chain\n\u003e files currently (Jan 2024) also include the following 3 CILogon CA certs, for legacy reasons.\n\u003e (these were copied across from the old SHA-1 cert chains):\n\n```shell\n    subject=DC = org, DC = cilogon, C = US, O = CILogon, CN = CILogon Basic CA 1\n    issuer=DC = org, DC = cilogon, C = US, O = CILogon, CN = CILogon Basic CA 1\n\n    subject=DC = org, DC = cilogon, C = US, O = CILogon, CN = CILogon OpenID CA 1\n    issuer=DC = org, DC = cilogon, C = US, O = CILogon, CN = CILogon OpenID CA 1\n\n    subject=DC = org, DC = cilogon, C = US, O = CILogon, CN = CILogon Silver CA 1\n    issuer=DC = org, DC = cilogon, C = US, O = CILogon, CN = CILogon Silver CA 1\n```\n\n### Creating and Signing Node Requests\n\n```shell\n  cd DataONEProdIntCA\n\n  openssl genrsa -passout pass:temp -des3 -out private/NodeNPass.key 2048\n\n  openssl rsa -passin pass:temp -in private/NodeNPass.key -out private/NodeN.key\n\n  rm private/NodeNPass.key\n\n  # NOTE: It's best to use the ca script to do this, because there isn't\n  # an openssl.cnf file in this directory - only a template\n  openssl req -config ./openssl.cnf -new -key private/NodeNPass.key -out req/NodeN.csr\n\n  # You will be prompted for the Common Name (CN) to set\n\n  openssl ca -config ./openssl.cnf  -create_serial -days 1095 \\\n    -out certs/NodeN.pem -infiles req/NodeN.csr\n\n  # You will be prompted for the key passphrase\n```\n\n### Signing a CSR\n\nIf a certificate signing request is provided, then it can be signed as follows:\n\n```shell\n  cd DataONETestIntCA\n  openssl ca \\\n    -config openssl.csr_ca.conf\n    -subj \"/DC=org/DC=dataone/CN=NODEID\" \\\n    -preserveDN -batch \\\n    -notext \\\n    -create_serial \\\n    -days 1095 \\\n    -out csr/NODEID.pem \\\n    -infiles csr/NODEID.csr.pem\n```\n\nWhere `NODEID` is the node identifier.\n\n\n### To revoke a certificate\n\n```shell\n  openssl ca -config ./openssl.cnf -revoke certs/NodeN.pem\n```\n\n### Creating the Test Root CA\n\n```shell\n  mkdir /var/ca\n  cd /var/ca\n  mkdir DataONETestRootCA\n  cd DataONETestRootCA\n  mkdir certs newcerts private req\n  touch index.txt\n  # Edit the openssl.cnf config file if needed; e.g. check the 'dir' entry in [ CA_default ].\n\n  openssl req -new -newkey rsa:4096 -keyout /Volumes/DATAONE/DataONETestRootCA.key \\\n    -out req/DataONETestRootCA.csr -config ./openssl.cnf\n\n  # You will be prompted for:\n  # 1. a passphrase to set for the new key, and\n  # 2. the Common Name (CN) to set\n\n  openssl ca -create_serial -out certs/DataONETestRootCA.pem -days 36500 \\\n    -keyfile /Volumes/DATAONE/DataONETestRootCA.key -selfsign -config ./openssl.cnf \\\n    -extensions v3_ca -infiles req/DataONETestRootCA.csr\n\n  # You will be asked for the key passphrase\n```\n\n### Creating the Test Intermediate CA\n\nThis is a cross-signed intermediate cert, in that it has the same subjectDN and public key as\nthe original DataONETestIntCA, but it is signed by the new sha256-based DataONETestRootCA.\n\n```shell\n  cd /var/ca\n  mkdir DataONETestIntCA\n  cd DataONETestIntCA\n  mkdir certs newcerts private req\n  touch index.txt\n\n  # No need to edit the config file; uses the one from the root CA\n\n  ###\n  # This is how we did it originally:\n  # ### OMIT FOR CROSS SIGNING ###\n  #   openssl req -new -newkey rsa:4096  -keyout /opt/DataONE/DataONETestIntCA.key \\\n  #   -out req/DataONETestIntCA.csr -config ../DataONETestCA/openssl.cnf\n  #\n  #   # You will be prompted for:\n  #   # 1. the Common Name (CN) to set, and\n  #   # 2. a passphrase to set for the new key\n  # ### END OMIT FOR CROSS SIGNING ###\n  #\n  # However, for cross-signing, we should NOT generate a new key (\" -newkey \"),\n  # but instead re-use the original intermediate key...\n  ###\n  openssl req -new -key /Volumes/DATAONE/SHA-1_ARCHIVE/DataONETestIntCA.key \\\n    -out req/DataONETestIntCA.csr -config ../DataONETestRootCA/openssl.cnf\n\n  # You will be prompted for:\n  # 1. the passphrase for the existing (test intermediate) key, and\n  # 2. the Common Name (CN) to set (NOTE for cross-signing, this MUST match the CN used in the old\n  #    intermediate cert!)\n\n  cd ../DataONETestRootCA\n\n  openssl ca -out ../DataONETestIntCA/certs/DataONETestIntCA.pem -days 36500 \\\n    -keyfile /Volumes/DATAONE/DataONETestRootCA.key -config ./openssl.cnf \\\n    -extensions v3_ca  -verbose -infiles ../DataONETestIntCA/req/DataONETestIntCA.csr\n\n  # You will be prompted for the passphrase for the existing (test root) key\n\n  # Create DataONETestIntCA/serial with serial number of the DataONETestIntCA.pem + something\n```\n\n### Creating the Test Certificate Chain File\n\n```shell\n  cd /var/ca\n  cat DataONETestCA/certs/DataONETestCA.pem \\\n    DataONETestIntCA/certs/DataONETestIntCA.pem \u003e DataONETestCAChain.crt\n```\n\n## Appendix 2: Certificate Cross-Signing\n\nWhen we started issuing DataONE node certificates in 2012, we were using SHA-1-encrypted Root\nand Intermediate CA certs. Since then, SHA-1 has widely been recognized as insecure, and has been\nreplaced with SHA-256. However, since it would be a huge task to re-issue all the node certificates\ncurrently in use, we need a way of upgrading our CA certs to SHA-256, whilst keeping them\nbackwards-compatible with existing node certs. This can be done by a process known as Cross Signing.\n(For an excellent overview of how cross signing works, see\n[Scott Helme's blog](https://scotthelme.co.uk/cross-signing-alternate-trust-paths-how-they-work/)).\n\nBasically, here's what happens when a DataONE Node cert (or any cert, for that matter) is created:\n\n1. the subscriber's information (name, domain name, etc...) is used to fill out a \"pre-certificate\".\n2. The pre-cert is then run through a hash function (SHA-256 in this case), to obtain its digest.\n3. That digest is then encrypted with the DataONE private key (the one that was used to create the\nIntermediate CA cert).\n4. This encrypted digest is the \"signature\", and once it is appended to the end of the\npre-cert, we now have a signed certificate that can be issued to the Subscriber.\n\n(It's interesting to note that this process does not require a root CA cert or an Intermediate CA\ncert; only the Intermediate's **private key** is needed).\n\nLater, when a DataONE Node cert is validated against the DataONE Intermediate CA cert (from the cert\nchain on the server), 2 things are checked:\n\n1. the signature on the bottom of the Node cert is decrypted using the Intermediate CA's public key.\nThis tells us that if the CA's public key can decrypt it, the CA's private key must have encrypted\nit, so **authenticity** has been verified.\n\n2. the server then calculates its own hash of the Pre-Certificate to compare to the hash stored in\nthe signature and determine if they are identical. If they match, the certificate has not been\ntampered with, so **Integrity** has been verified.\n\nNow we know we can trust the contents of the Node cert, authentication can be completed by simply\nverifying that the \"Issuer\" field in the Node cert matches the \"Subject\" field in the Intermediate\ncert.\n\nSo - in summary - only 2 pieces of information from the Intermediate certificate are used to\nauthenticate the Node cert:\n\n1. the public key (used to decrypt the signature), and\n2. the Subject (used to verify the Issuer)\n\nTherefore, **it is possible to have two (or multiple) different versions of the Intermediate cert,**\n**provided they each contain the same public key and the same Subject!**\n\nThis is why cross signing is possible.\n\nSo - all we need to do, in order to create a cross-signed SHA-256 Intermediate is:\n\n1. Create a new SHA-256 self-signed Root CA cert\n2. For the Intermediate cert, first create a certificate signing request (CSR), ensuring 2 things:\n   1. The \"Subject\" exactly matches the one in the old SHA-1 Intermediate cert.\n   2. The CSR is signed by the ORIGINAL private key that was used to sign the old SHA-1 Intermediate\n      CSR.\n      * (The public key that will be included in the final cert is generated from this private key,\n        so if we use the same private key, the new public key in the new Intermediate cert should\n        match the old public key in the old Intermediate cert)\n3. Now create the new Intermediate cert from this CSR, signing it with the new Root CA Private Key\n   from step (1) above.\n\nNow we can replace the old sha-1 CA cert chain with this new SHA-256-based CA chain, and it will\nwork with all the existing Node certificates and any new Node certs issued against the new CA.\n\n(Final note; \"Cross signing\" is a misnomer. it implies that one intermediate certificate is signed\nby two different Root CAs. This is not the case, as can be seen above.)\n\n## Appendix 3: Directory Structure\n\n```\n── ca\n   ├── DataONEProdIntCA\n   ├── DataONEProdRootCA\n   ├── DataONETestIntCA\n   ├── DataONETestRootCA\n   └── SHA-1_ARCHIVE              ## SHA-1 content from old top-level ca directory moved here:\n       ├── DataONEProdCA          ## old SHA-1 Prod Intermediate CA\n       ├── DataONERootCA          ## old SHA-1 Prod Root CA\n       ├── DataONETestCA          ## old SHA-1 Test Root CA\n       └── DataONETestIntCA       ## old SHA-1 Test Intermediate CA\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdataoneorg%2Fca","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdataoneorg%2Fca","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdataoneorg%2Fca/lists"}