easy-rsa icon indicating copy to clipboard operation
easy-rsa copied to clipboard

Add commands to publish certificate to a different location after signing

Open JulienVdG opened this issue 8 years ago • 16 comments

Hello, a pull-request to add a 'publish' feature to easy-rsa.

The rational is as follows: I use easy-rsa at two locations, lets call them SHARED and PRIVATE. SHARED is used to generate request and to publish the results, it does not contains a CA. It can be accessed/mounted to install the certificate on the servers or client. PRIVATE contains the CA certificate. PRIVATE can access SHARED but nothing else, it does not have network access. The commands added in this set of commit help handle this case.

A typical usage is:

In SHARED run: easy-rsa gen-req my_server In PRIVATE set the variable EASYRSA_PUBLISH to SHARED and run: easy-rsa import-req my_server easy-rsa sign server my_server easy-rsa publish-ca update Then SHARED contains all the needed files but not the private key of the CA.

The pull-request also contains two patch not directly related to the feature, tell me if you prefer to have separate pull-requests for them instead.

Best Regards,

Julien VdG

JulienVdG avatar Jun 14 '17 21:06 JulienVdG

I like this idea, but I'm not sure it belongs within Easy-RSA itself. This sounds more like a wrapper function.

ecrist avatar Jun 30 '17 23:06 ecrist

I know, I first planned to do it as a wrapper script, but this was a lot of redoing the same logic as in Easy-RSA to configure folders to manage commands and so on. So I ended up adding it to Easy-RSA proper and doing a wrapper script for functions that really are more 'batch' use (see https://github.com/JulienVdG/raspki/blob/master/overlay/usr/bin/raspki ). So I tried to write it with configuration variables so that basic usage is not modified.

But I can understand if you don't want to integrate it as it means you'll have to maintain it for ever after... I'll keep my fork for my own use.

Best regards, JulienVdG

JulienVdG avatar Jul 02 '17 08:07 JulienVdG

My concern is mostly due to cross platform functionality. This is a feature that would work well on Linux but doesn't scale to Windows.

If it worked on both I'd happily include it in base.

Eric Crist

On Jul 2, 2017, at 3:08 AM, Julien Viard de Galbert [email protected] wrote:

I know, I first planned to do it as a wrapper script, but this was a lot of redoing the same logic as in Easy-RSA to configure folders to manage commands and so on. So I ended up adding it to Easy-RSA proper and doing a wrapper script for functions that really are more 'batch' use (see https://github.com/JulienVdG/raspki/blob/master/overlay/usr/bin/raspki ). So I tried to write it with configuration variables so that basic usage is not modified.

But I can understand if you don't want to integrate it as it means you'll have to maintain it for ever after... I'll keep my fork for my own use.

Best regards, JulienVdG

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or mute the thread.

ecrist avatar Jul 02 '17 14:07 ecrist

Oh, so you're asking to test and fix it on Windows before a possible integration. That's fair.

JulienVdG avatar Jul 02 '17 15:07 JulienVdG

By reviewing my patches (I don't have windows to test here) I think only the last one "Add status command..." looks non portable.

JulienVdG avatar Jul 02 '17 17:07 JulienVdG

By reviewing my patches (I don't have windows to test here) I think only the last one "Add status command..." looks non portable.

JulienVdG avatar Jul 14 '17 12:07 JulienVdG

Is this in a ready-state? If so, I'll review it.

ecrist avatar Sep 12 '17 14:09 ecrist

Well I didn't test it on windows - I only tried with a previous release where the windows binary were missing so I failed. But as md5sum is part of the added binaries, I think even the Status command will work on windows... Again, I didn't test it on windows yet so no guaranties on that front. And I really don't know when I'll find time and motivation to boot windows :)

JulienVdG avatar Sep 13 '17 07:09 JulienVdG

Hello,

I started to rebase on 3.0.5 release.

I wanted to do my first tests on windows, (last year I tested on the release that missed the binaries...) but it does not seam to work... I'm getting an error: "cannot create /dev/null: Invalid argument"

The sh.exe binary is a release (or a preview?) from 2013 !! None of the binaries have proper source or link to actual source (only name of project and mksh/win32 does not seam to exist anymore or I couldn't find the webpage).

Do you still really want to support windows ?

To be fair, I tested on a fresh install of ReactOS (because I don't have any windows at hand)

Then I installed git (https://gitforwindows.org/) and using git bash I could launch bin/easyrsa-shell-init.sh so I'll be able to test, but not with the provided binaries ... so is there any point ?

JulienVdG avatar Nov 26 '18 21:11 JulienVdG

~~I use this for Windows testing: https://sites.google.com/site/easylinuxtipsproject/oldgrub~~

TinCanTech avatar Nov 26 '18 22:11 TinCanTech

Better late than never ! I found time to rebase all this :tada:

JulienVdG avatar Oct 14 '20 22:10 JulienVdG

I'm out of town for the rest of October, but will look into this and pull it in if it looks good when I return.

ecrist avatar Oct 15 '20 02:10 ecrist

IMHO this should be a wrapper script.

If you do this on your own independent repo then you have full control.

TinCanTech avatar Mar 22 '22 21:03 TinCanTech

As a wrapper script it would duplicate a lot of easyrsa's code, I also use a wrapper for more features but this was better here... Anyway I understand, and won't probably have time to update this soon so I agree with the maybe-someday tag !

JulienVdG avatar Mar 23 '22 11:03 JulienVdG

As I understand it, your essential goal is to publish public and private data to different places but EasyRSA does not provide a suitable structure.

I'll take a closer look some time but for now, this is not a priority.

TinCanTech avatar Mar 23 '22 14:03 TinCanTech

Something brewing ..

TinCanTech avatar Jun 04 '22 22:06 TinCanTech

Required:

  • $EASYRSA_ISSUED: Option --issued=<DIR> [Not in PKI]

Insert $EASYRSA_ISSUED where required. eg. build-ca

TinCanTech avatar Oct 21 '22 21:10 TinCanTech

Hello I did a simple rebase of my old code. I think you have other ideas on how to implement this feature, so it might not be that useful. Anyway there are a few commits in there that are not completely related to the main feature (they should probably be split out of this MR but I had enough rebase conflicts for today :smile: ) so I'm trying to keep my branch up to date with easyrsa from time to time.

JulienVdG avatar Oct 22 '22 08:10 JulienVdG

Oh I think I just got the $EASYRSA_ISSUED idea: You propose to make the pki/issued directory configurable so that easyrsa can write the output directly outside of the pki directory. While my approach was to copy the issued files to the external directory with a new command. Is that so ?

JulienVdG avatar Oct 22 '22 08:10 JulienVdG

You propose to make the pki/issued directory configurable so that easyrsa can write the output directly outside of the pki directory.

Exactly. However, that is not set in stone.

Your approach still has merit, in that the standard PKI remains intact.

FYI: This PR requires a signature. Also, I prefer that PRs use a new branch, not master. We can sort those issues out in time.

TinCanTech avatar Oct 22 '22 10:10 TinCanTech

@JulienVdG I prefer your approach of the new command: publish-cert

There are some things that I'm not keen on though..

TinCanTech avatar Oct 22 '22 12:10 TinCanTech

@JulienVdG Can you explain what value there is to you by stripping the certificate text output ?

TinCanTech avatar Oct 22 '22 17:10 TinCanTech

@JulienVdG Can you explain what value there is to you by stripping the certificate text output ?

Some software will fail to read the certificate if there is anything but the -----HEADER / FOOTER----- and the base64 cert data. Off the top of my head, some asn1 parsers including "openssl asn1parse".

dekeonus avatar Oct 22 '22 21:10 dekeonus

@JulienVdG Can you explain what value there is to you by stripping the certificate text output ?

Some software will fail to read the certificate if there is anything but the -----HEADER / FOOTER----- and the base64 cert data. Off the top of my head, some asn1 parsers including "openssl asn1parse".

I have reopened #624 in order to reconsider this problem.

Adding a single option to building a certificate without the public/human readable text appears to be the most logical solution.

Due to renew and all that, it may be desirable to have an easyrsa built-in function to out put a bare-bones certificate. PRs may be welcome for such a function.

eg: strip_cert() .. type of thing.

TinCanTech avatar Oct 22 '22 21:10 TinCanTech

Adding a single option to building a certificate without the public/human readable text appears to be the most logical solution.

Due to renew and all that, it may be desirable to have an easyrsa built-in function to out put a bare-bones certificate. PRs may be welcome for such a function.

eg: strip_cert() .. type of thing.

I'd prefer this strip_cert() idea.

For my workflow I like having the easyrsa/pki certs with the cert text included: I can read basename.crt OR serial.crt with a pager / tail / cat and know what the cert was. I'm still not sure what service I am (or was) running that barfed on cert text in the cert bundle.

dekeonus avatar Oct 22 '22 21:10 dekeonus

Please, keep in mind that strip_cert() (Or a better name) is probably plumbing not porcelain. It needs to be an option that could work with an existing certificate but probably not over-write the source. Building a new certificate can be bare-bones because it is the source file.

TinCanTech avatar Oct 22 '22 21:10 TinCanTech

what is the purpose of easyrsa3/x509-types/COMMON-SECTIONS ? easyrsa currently has no means to handle raw extensions. If raw extension support was added it would need to be specifically added to the end of generated temporary extension file.

The COMMON-SECTIONS as written looks as though basicConstraints, kU, eKU from the other x509-types/foo would be appended to that [ crlDistributionPoints_values ] section which would not be what a user wants.

dekeonus avatar Oct 22 '22 21:10 dekeonus

It might be a nice-to-have if publish_ca() had some means to prep for a ca-bundle: i.e. that successive easyrsa publish-ca from the rootCA through subCAs would enable one to have a cachain.crt available at the working (non-ca) easyrsa/pki location

dekeonus avatar Oct 22 '22 21:10 dekeonus

@dekeonus Hi :-)

I have an alternative version to this "publishing" branch (To be pushed), which is only concerned with copying files to the public folder.

The other details are not relevant to this PR, they are only included as part of @JulienVdG source (Which is also from his master and, therefore, unacceptable as a genuine PR. Further details are here).

This PR also remains unsigned. As it should remain.

TinCanTech avatar Oct 22 '22 21:10 TinCanTech

Draft diff:

diff --git a/easyrsa3/easyrsa b/easyrsa3/easyrsa
index a0e5652..eafe44b 100755
--- a/easyrsa3/easyrsa
+++ b/easyrsa3/easyrsa
@@ -3031,6 +3031,89 @@ location: $pkcs_out"
        return 0
 } # => export_pkcs()
 
+# Publish a file
+# Required parameters:
+# 1: Full source directory. eg: /etc/easy-rsa/pki/issued
+# 2: Source File name. eg: server.crt
+# 3: Destination File name. Optional. eg: other-name.crt
+publish_file() {
+       # Public directory must exist
+       if [ "$EASYRSA_PUBLIC" ]; then
+               mkdir -p "$EASYRSA_PUBLIC" || die "\
+publish_file - Public directory access violation: '$EASYRSA_PUBLIC'"
+       else
+               die "\
+publish_file - Public directory undefined."
+       fi
+
+       # Source directory must be specified and exist
+       source_d="$1"; shift || die "\
+publish_file - Missing input: 'source_d'"
+       [ -d "$source_d" ] || die "\
+publish_file - Source directory missing: '$source_d'"
+
+       # Input file name must be specified and exist
+       name_in="$1"; shift || die "\
+publish_file - Missing input: 'name_in'"
+       file_in="${source_d}/${name_in}"
+       [ -f "$file_in" ] || die "\
+publish_file - Source file missing: '$file_in'"
+
+       # Output file can be renamed
+       if [ "$1" ]; then
+               file_out="${EASYRSA_PUBLIC}/$1"
+       else
+               file_out="${EASYRSA_PUBLIC}/${name_in}"
+       fi
+       file_out_tmp="${file_out}.easyrsa-temp"
+
+       # Verify input file
+       # TODO
+       # "strip" input file.. TODO
+
+       # Copy input to temporary output
+       if cp "$file_in" "$file_out_tmp"; then
+               # Over write any other file of the same output name
+               if mv -f "$file_out_tmp" "$file_out"; then
+                       notice "\
+File successfully published to:
+* $file_out"
+               else
+                       rm -f "$file_out_tmp"
+                       die "\
+publish_file - Failed to publish file: '$file_in'"
+               fi
+       else
+               rm -f "$file_out_tmp"
+               die "\
+publish_file - Failed to copy source file to public directory."
+       fi
+} # => publish_file()
+
+# Publish certificate
+publish_cert() {
+       publish_file "$EASYRSA_PKI/issued" "$1.crt" "$2.crt"
+} # => publish_cert()
+
+# Publish CA
+publish_ca() {
+       publish_file "$EASYRSA_PKI" "ca.crt"
+} # => publish_ca()
+
+# Publish CRL
+publish_crl() {
+       # <- gen_crl
+       publish_file "$EASYRSA_PKI" "crl.crt"
+} # => publish_crl()
+
+# Publish for OSCP
+publish_oscp() {
+       # example
+       publish_ca
+       publish_crl
+       # <- update_db
+       publish_file "$EASYRSA_PKI" "index.txt"
+} # => publish_oscp()
+
 # set-pass backend
 set_pass() {
        # Verify PKI has been initialised
@@ -4188,6 +4271,7 @@ Sourcing the vars file and building certificates will probably fail ..'
        set_var EASYRSA_TEMP_DIR                "$EASYRSA_PKI"
        set_var EASYRSA_REQ_CN                  ChangeMe
        set_var EASYRSA_DIGEST                  sha256
+       set_var EASYRSA_PUBLIC                  "$EASYRSA_PKI/public"
 
        set_var EASYRSA_SSL_CONF                "$EASYRSA_PKI/openssl-easyrsa.cnf"
        set_var EASYRSA_SAFE_CONF               "$EASYRSA_PKI/safessl-easyrsa.cnf"
@@ -4945,6 +5029,9 @@ while :; do
        --tmp-dir)
                export EASYRSA_TEMP_DIR="$val"
                ;;
+       --pub-dir)
+               export EASYRSA_PUBLIC="$val"
+               ;;
        --ssl-conf)
                export EASYRSA_SSL_CONF="$val"
                ;;
@@ -5164,6 +5251,23 @@ case "$cmd" in
        export-p1)
                export_pkcs p1 "$@"
                ;;
+       publish-ca)
+               publish_ca "$@"
+               ;;
+       publish-crl)
+               publish_crl "$@"
+               ;;
+       publish-oscp)
+               publish_oscp "$@"
+               ;;
+       publish-pkcs)
+               #publish_pkcs "$@"
+               print "Not currently available: publish-pkcs"
+               easyrsa_error_exit=1
+               ;;
+       publish-cert)
+               publish_cert "$@"
+               ;;
        set-rsa-pass)
                set_pass rsa "$@"
                ;;

TinCanTech avatar Oct 22 '22 22:10 TinCanTech

to easily get cert without text, one could extend publish_file() to have an optional (either arg 3 or 4) notext option. (and a corresponding case / if-else [ "file_ext" = "crt" ] to replace cp ... with easyrsa_openssl x509 -in "$file_in" -out "$file_out_tmp" ... )

dekeonus avatar Oct 22 '22 22:10 dekeonus