2022-10-22 11:17:29 +00:00
|
|
|
// Package openssl shells out openssl for testing
|
2018-11-14 14:13:28 +00:00
|
|
|
package openssl
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"crypto"
|
|
|
|
"crypto/x509"
|
|
|
|
"encoding/pem"
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
|
|
|
"os/exec"
|
2018-12-10 16:18:29 +00:00
|
|
|
"strings"
|
2018-11-14 14:13:28 +00:00
|
|
|
)
|
|
|
|
|
2018-12-10 16:18:29 +00:00
|
|
|
// SMIME is the commpand used for openssl smime, can be replaces with cms
|
|
|
|
var SMIME = "smime"
|
|
|
|
|
2022-10-22 11:17:29 +00:00
|
|
|
// Encrypt a message with openssl
|
2018-11-19 13:33:55 +00:00
|
|
|
func Encrypt(in []byte, cert *x509.Certificate, opts ...string) (der []byte, err error) {
|
2018-11-14 14:13:28 +00:00
|
|
|
|
2018-12-10 16:18:29 +00:00
|
|
|
tmpKey, err := ioutil.TempFile("", "example")
|
|
|
|
defer os.Remove(tmpKey.Name())
|
2018-11-14 14:13:28 +00:00
|
|
|
|
2018-12-10 16:18:29 +00:00
|
|
|
pem.Encode(tmpKey, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw})
|
2018-11-14 14:13:28 +00:00
|
|
|
|
2018-12-10 16:18:29 +00:00
|
|
|
param := []string{SMIME, "-encrypt", "-aes128"}
|
2018-12-21 13:43:59 +00:00
|
|
|
if SMIME == "smime" {
|
|
|
|
// For smime arguments can not be passed after the keyfile
|
|
|
|
param = append(param, opts...)
|
|
|
|
param = append(param, tmpKey.Name())
|
|
|
|
} else {
|
|
|
|
// Keyots have to be passed after the key
|
|
|
|
param = append(param, "-recip", tmpKey.Name())
|
|
|
|
param = append(param, opts...)
|
|
|
|
}
|
2018-11-19 13:33:55 +00:00
|
|
|
der, err = openssl(in, param...)
|
2018-11-14 14:13:28 +00:00
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-10-22 11:17:29 +00:00
|
|
|
// Decrypt a message with openssl
|
2018-11-19 13:33:55 +00:00
|
|
|
func Decrypt(in []byte, key crypto.PrivateKey, opts ...string) (plain []byte, err error) {
|
2018-11-14 14:13:28 +00:00
|
|
|
|
2018-12-10 16:18:29 +00:00
|
|
|
tmpKey, err := ioutil.TempFile("", "example")
|
|
|
|
defer os.Remove(tmpKey.Name())
|
2018-11-14 14:13:28 +00:00
|
|
|
|
2018-12-10 16:18:29 +00:00
|
|
|
keyDER, err := x509.MarshalPKCS8PrivateKey(key)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
pem.Encode(tmpKey, &pem.Block{Type: "PRIVATE KEY", Bytes: keyDER})
|
2018-11-14 14:13:28 +00:00
|
|
|
|
2018-12-10 16:18:29 +00:00
|
|
|
param := []string{SMIME, "-decrypt"}
|
2018-11-19 13:33:55 +00:00
|
|
|
param = append(param, opts...)
|
2018-12-10 16:18:29 +00:00
|
|
|
param = append(param, []string{"-inkey", tmpKey.Name()}...)
|
2018-11-19 13:33:55 +00:00
|
|
|
plain, err = openssl(in, param...)
|
2018-11-14 14:13:28 +00:00
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-12-10 16:18:29 +00:00
|
|
|
// SignDetached creates a detached signature with openssl
|
2018-11-19 13:33:55 +00:00
|
|
|
func SignDetached(in []byte, cert *x509.Certificate, key crypto.PrivateKey, interm []*x509.Certificate, opts ...string) (plain []byte, err error) {
|
2018-11-14 14:13:28 +00:00
|
|
|
|
|
|
|
tmpCert, err := ioutil.TempFile("", "example")
|
|
|
|
defer os.Remove(tmpCert.Name())
|
|
|
|
|
|
|
|
pem.Encode(tmpCert, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw})
|
|
|
|
|
|
|
|
tmpKey, err := ioutil.TempFile("", "example")
|
|
|
|
defer os.Remove(tmpKey.Name())
|
|
|
|
|
2018-12-10 16:18:29 +00:00
|
|
|
keyDER, err := x509.MarshalPKCS8PrivateKey(key)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
pem.Encode(tmpKey, &pem.Block{Type: "PRIVATE KEY", Bytes: keyDER})
|
2018-11-14 14:13:28 +00:00
|
|
|
|
|
|
|
tmpInterm, err := ioutil.TempFile("", "example")
|
|
|
|
defer os.Remove(tmpInterm.Name())
|
|
|
|
|
|
|
|
for _, i := range interm {
|
|
|
|
pem.Encode(tmpInterm, &pem.Block{Type: "CERTIFICATE", Bytes: i.Raw})
|
|
|
|
}
|
|
|
|
|
2018-12-21 13:43:59 +00:00
|
|
|
param := []string{SMIME, "-sign", "-nodetach", "-signer", tmpCert.Name(), "-inkey", tmpKey.Name(), "-certfile", tmpInterm.Name()}
|
2018-11-19 13:33:55 +00:00
|
|
|
param = append(param, opts...)
|
|
|
|
plain, err = openssl(in, param...)
|
2018-11-14 14:13:28 +00:00
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-12-10 16:18:29 +00:00
|
|
|
// Sign creates a signature with openssl
|
2018-11-19 13:33:55 +00:00
|
|
|
func Sign(in []byte, cert *x509.Certificate, key crypto.PrivateKey, interm []*x509.Certificate, opts ...string) (plain []byte, err error) {
|
2018-11-14 14:13:28 +00:00
|
|
|
|
|
|
|
tmpCert, err := ioutil.TempFile("", "example")
|
|
|
|
defer os.Remove(tmpCert.Name())
|
|
|
|
|
|
|
|
pem.Encode(tmpCert, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw})
|
|
|
|
|
|
|
|
tmpKey, err := ioutil.TempFile("", "example")
|
|
|
|
defer os.Remove(tmpKey.Name())
|
|
|
|
|
2018-12-10 16:18:29 +00:00
|
|
|
keyDER, err := x509.MarshalPKCS8PrivateKey(key)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
pem.Encode(tmpKey, &pem.Block{Type: "PRIVATE KEY", Bytes: keyDER})
|
2018-11-14 14:13:28 +00:00
|
|
|
|
|
|
|
tmpInterm, err := ioutil.TempFile("", "example")
|
|
|
|
defer os.Remove(tmpInterm.Name())
|
|
|
|
|
|
|
|
for _, i := range interm {
|
|
|
|
pem.Encode(tmpInterm, &pem.Block{Type: "CERTIFICATE", Bytes: i.Raw})
|
|
|
|
}
|
|
|
|
|
2018-12-10 16:18:29 +00:00
|
|
|
param := []string{SMIME, "-sign"}
|
2018-11-19 13:33:55 +00:00
|
|
|
param = append(param, opts...)
|
|
|
|
param = append(param, []string{"-signer", tmpCert.Name(), "-inkey", tmpKey.Name(), "-certfile", tmpInterm.Name()}...)
|
|
|
|
plain, err = openssl(in, param...)
|
2018-11-14 14:13:28 +00:00
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-10-22 11:17:29 +00:00
|
|
|
// Verify a signature with openssl
|
2018-11-19 13:33:55 +00:00
|
|
|
func Verify(in []byte, ca *x509.Certificate, opts ...string) (plain []byte, err error) {
|
2018-11-14 14:13:28 +00:00
|
|
|
|
|
|
|
tmpCA, err := ioutil.TempFile("", "example")
|
|
|
|
defer os.Remove(tmpCA.Name())
|
|
|
|
|
|
|
|
pem.Encode(tmpCA, &pem.Block{Type: "CERTIFICATE", Bytes: ca.Raw})
|
|
|
|
|
2018-12-10 16:18:29 +00:00
|
|
|
param := []string{SMIME, "-verify"}
|
2018-11-19 13:33:55 +00:00
|
|
|
param = append(param, opts...)
|
|
|
|
param = append(param, []string{"-CAfile", tmpCA.Name()}...)
|
|
|
|
plain, err = openssl(in, param...)
|
2018-11-14 14:13:28 +00:00
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-12-10 16:18:29 +00:00
|
|
|
// Openssl runs the openssl command with given args
|
|
|
|
func Openssl(stdin []byte, args ...string) ([]byte, error) {
|
|
|
|
return openssl(stdin, args...)
|
|
|
|
}
|
|
|
|
|
2018-11-14 14:13:28 +00:00
|
|
|
func openssl(stdin []byte, args ...string) ([]byte, error) {
|
|
|
|
cmd := exec.Command("openssl", args...)
|
|
|
|
|
|
|
|
in := bytes.NewReader(stdin)
|
|
|
|
out := &bytes.Buffer{}
|
|
|
|
errs := &bytes.Buffer{}
|
|
|
|
|
|
|
|
cmd.Stdin, cmd.Stdout, cmd.Stderr = in, out, errs
|
|
|
|
|
|
|
|
if err := cmd.Run(); err != nil {
|
|
|
|
if len(errs.Bytes()) > 0 {
|
|
|
|
return nil, fmt.Errorf("error running %s (%s):\n %v", cmd.Args, err, errs.String())
|
|
|
|
}
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2018-12-10 16:18:29 +00:00
|
|
|
if strings.Contains(errs.String(), "Error") {
|
|
|
|
return nil, fmt.Errorf("error running %s (%s):\n ", cmd.Args, errs.String())
|
|
|
|
}
|
|
|
|
|
2018-11-14 14:13:28 +00:00
|
|
|
return out.Bytes(), nil
|
|
|
|
}
|