Skip to content

Commit

Permalink
Create CSR in Transit, sign with PKI (hashicorp#17630)
Browse files Browse the repository at this point in the history
Execute with:

$ go test -v -run=TestTransitPKICSR github.com/hashicorp/vault/builtin/logical/transit
...
    backend_test.go:1843: csr: -----BEGIN CERTIFICATE REQUEST-----
        MIICXjCCAUYCAQAwGTEXMBUGA1UEAxMOZGFkZ2FyY29ycC5jb20wggEiMA0GCSqG
        SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDD8GUy2Rut9ILPXH/Ef7lEaYijuBB9wogd
        hKD3uJyfK5PqBqM8166UsrP7Y+bWkwDrMke3aDxXRNybys33kIc8KfGwS3omNYd3
        17KN1D4ZgQ+oW6xISa3ISOl4D7XeFtHeTP0U1plVXBd9kqTlo4YPlUF/kTfqmxDu
        2a41BIS5HlORdLLG+jQ3shRgwHANONBhlaUnIqEeykdW8/iEBlqoYlMzty9W724R
        2mKk0FzrVAZ/X5ZO992dAMrQDvc3Nofl+ddzbElBJLumrcDSwALFVge+ag1N48kE
        CCfxjizEykGdCrR+VELb8b33IgFf6EOVRnS5Qy8whmw943v5Oru5AgMBAAGgADAN
        BgkqhkiG9w0BAQsFAAOCAQEAdg9SwbrWszMmz60JWQPPfwW+XhzR0MdY82adK8P6
        9xpWyJU+U649tAFQb+PCT1OcU7ETd59QcEV38VLndBPWhotTXl5oB5XAqg2bkKHV
        nLc0cGwyxBSs77LALc//m2f5v2otO9fLOmuM2RMfD02ZUliBmZUzeaUIJYEfT+cS
        M60uLKJvnNBu5xH1q0oG9P0uNkpEX+QGx6SwhR1/41pmygiUR+uwJxxuRGMvECoN
        dsHZtzi7ftEHBJ9tk94hd/RFnDsvWlHGyfRWhALNtbo6QjHxjBJIFKh+GHlI8Tnf
        6YWvD0VIodE609+RlCrhFlGd+3NUSt0b/f0bgkMJLzLqEw==
        -----END CERTIFICATE REQUEST-----
    backend_test.go:1878: root: -----BEGIN CERTIFICATE-----
        MIIDHTCCAgWgAwIBAgIUIwCzCdrsgkcNOi5liRNHeH+n+tUwDQYJKoZIhvcNAQEL
        BQAwFjEUMBIGA1UEAxMLUEtJIFJvb3QgWDEwHhcNMjIxMDIxMTQ1NjQyWhcNMjIx
        MTIyMTQ1NzExWjAWMRQwEgYDVQQDEwtQS0kgUm9vdCBYMTCCASIwDQYJKoZIhvcN
        AQEBBQADggEPADCCAQoCggEBAMdM65f5p3fLwQP1sezBRFqAxUZhOQwnnnp8mFXp
        3fIF9pqLMzNvyd+bCUXv+aFalX4KY1iOoKVHJWwtpXMoKn40U+DZkapR9CsVQt5Q
        9xzIcuPPuI+/oNwU4qB9mAuwG+U7KLosGnQOR3NI02A4dnl5I0z8Y/DJLz29GP/P
        1zPYMBRBpkMz4F2Xr0w6tTXWDsmqZ9j7ukBDoizmnB2xfKzSjCVmQvXa71UlqbG9
        td75LCgpiQh/50mHFHs6RKtqrlFUY5BtPPs+tHUf4nklieIzbAEwA8Fbq4d/Xpq1
        HRoRvWj3nelX/h/IRlj/VKJssd1ZL+1kdzxKB4N6AFC1nusCAwEAAaNjMGEwDgYD
        VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFCniHbjHy/UG
        ShROBOiikqxCe+OkMB8GA1UdIwQYMBaAFCniHbjHy/UGShROBOiikqxCe+OkMA0G
        CSqGSIb3DQEBCwUAA4IBAQBSKnl154oyc1Rncm4sr/1f1QM5rCaw/lqgISfvki8m
        t6yyxQL+9lDpebFjBDTL5teRzuMYyqN4pRkIhpITDGmFXRpEOv14mcbASX7nPBEN
        bYXhOh1UC8a0CLzT2ll0ERFNnUEPRi0s0ONRm3lIZAV3Mzf4sOdwfRwmP33hBe/1
        V9D7Lcx5N84EPrvGC/r8F/PsVKHyKFS46qB1MvhMppRG6fJ2cFmg5UGwdKdmxuvz
        FoT+RaTLkgcQgkDuYClNco5OVIM7Bd4JTNK3WbqvtGklOHslrz+ND0eMYM/LK+ZS
        zNM35nzK6QaN2M4IO4Wuy3y2yu8xllEfmssXwAtTi4wk
        -----END CERTIFICATE-----
    backend_test.go:1879: leaf: -----BEGIN CERTIFICATE-----
        MIIDDzCCAfegAwIBAgIUBGeUSi0p3ffndZqgvlBvMvn8qgMwDQYJKoZIhvcNAQEL
        BQAwFjEUMBIGA1UEAxMLUEtJIFJvb3QgWDEwHhcNMjIxMDIxMTQ1NjQyWhcNMjIx
        MDIxMTUwNzEyWjAZMRcwFQYDVQQDEw5kYWRnYXJjb3JwLmNvbTCCASIwDQYJKoZI
        hvcNAQEBBQADggEPADCCAQoCggEBAMPwZTLZG630gs9cf8R/uURpiKO4EH3CiB2E
        oPe4nJ8rk+oGozzXrpSys/tj5taTAOsyR7doPFdE3JvKzfeQhzwp8bBLeiY1h3fX
        so3UPhmBD6hbrEhJrchI6XgPtd4W0d5M/RTWmVVcF32SpOWjhg+VQX+RN+qbEO7Z
        rjUEhLkeU5F0ssb6NDeyFGDAcA040GGVpScioR7KR1bz+IQGWqhiUzO3L1bvbhHa
        YqTQXOtUBn9flk733Z0AytAO9zc2h+X513NsSUEku6atwNLAAsVWB75qDU3jyQQI
        J/GOLMTKQZ0KtH5UQtvxvfciAV/oQ5VGdLlDLzCGbD3je/k6u7kCAwEAAaNSMFAw
        DgYDVR0PAQH/BAQDAgOoMB0GA1UdDgQWBBSRCRR/62DjS1kjWHrVQ0Y58leUbDAf
        BgNVHSMEGDAWgBQp4h24x8v1BkoUTgToopKsQnvjpDANBgkqhkiG9w0BAQsFAAOC
        AQEAvWPLGqtC1SRy61Y17HtJ0giDUwpCZbOUkAwtdDAnKIhR1v4wrlY3sKUBLuhK
        xOJIWfVlCnPUt5uTnPaWyVyUfry6YNerish1k7ny/R1n58PjsPhUg8GJB9HHsME+
        gQQ22z6D/87n0bEE8PaTzIU6+cVHoIBJ0rqzjZVkBs0cEjf+l40RPP1h+ZiTw27u
        CR2iXmHJ9TQ8ZBWygIhxB9JOMbk5jpH6w6wJqq8XK9zuC1hlYbXH1K5KvZJxAPlh
        CJkoq2KxaIwByTHjRdGjDogSibsyY+CxQUnktefXb6tYKvFTpUFsh1fjQRCwUrlD
        SExMRHhFJBHfyPD1w26N3IjRlg==
        -----END CERTIFICATE-----

Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>

Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
  • Loading branch information
cipherboy authored and jayant07-yb committed Mar 15, 2023
1 parent 39b5231 commit 510f1ab
Showing 1 changed file with 162 additions and 1 deletion.
163 changes: 162 additions & 1 deletion builtin/logical/transit/backend_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ package transit

import (
"context"
"crypto"
cryptoRand "crypto/rand"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"fmt"
"io"
"math/rand"
"os"
"path"
Expand All @@ -15,13 +19,20 @@ import (
"testing"
"time"

uuid "github.com/hashicorp/go-uuid"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/builtin/logical/pki"
logicaltest "github.com/hashicorp/vault/helper/testhelpers/logical"
vaulthttp "github.com/hashicorp/vault/http"
"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/helper/consts"
"github.com/hashicorp/vault/sdk/helper/keysutil"
"github.com/hashicorp/vault/sdk/logical"
"github.com/hashicorp/vault/vault"

uuid "github.com/hashicorp/go-uuid"
"github.com/mitchellh/mapstructure"

"github.com/stretchr/testify/require"
)

const (
Expand Down Expand Up @@ -1858,3 +1869,153 @@ func testTransit_AEAD(t *testing.T, keyType string) {
t.Fatalf("bad expected error: err: %v\nresp: %#v", err, resp)
}
}

// Hack: use Transit as a signer.
type transitKey struct {
public any
mount string
name string
t *testing.T
client *api.Client
}

func (k *transitKey) Public() crypto.PublicKey {
return k.public
}

func (k *transitKey) Sign(_ io.Reader, digest []byte, opts crypto.SignerOpts) (signature []byte, err error) {
hash := opts.(crypto.Hash)
if hash.String() != "SHA-256" {
return nil, fmt.Errorf("unknown hash algorithm: %v", opts)
}

resp, err := k.client.Logical().Write(k.mount+"/sign/"+k.name, map[string]interface{}{
"hash_algorithm": "sha2-256",
"input": base64.StdEncoding.EncodeToString(digest),
"prehashed": true,
"signature_algorithm": "pkcs1v15",
})
if err != nil {
return nil, fmt.Errorf("failed to sign data: %w", err)
}
require.NotNil(k.t, resp)
require.NotNil(k.t, resp.Data)
require.NotNil(k.t, resp.Data["signature"])
rawSig := resp.Data["signature"].(string)
sigParts := strings.Split(rawSig, ":")

decoded, err := base64.StdEncoding.DecodeString(sigParts[2])
if err != nil {
return nil, fmt.Errorf("failed to decode signature (%v): %w", rawSig, err)
}

return decoded, nil
}

func TestTransitPKICSR(t *testing.T) {
coreConfig := &vault.CoreConfig{
LogicalBackends: map[string]logical.Factory{
"transit": Factory,
"pki": pki.Factory,
},
}

cluster := vault.NewTestCluster(t, coreConfig, &vault.TestClusterOptions{
HandlerFunc: vaulthttp.Handler,
})
cluster.Start()
defer cluster.Cleanup()

cores := cluster.Cores

vault.TestWaitActive(t, cores[0].Core)

client := cores[0].Client

// Mount transit, write a key.
err := client.Sys().Mount("transit", &api.MountInput{
Type: "transit",
})
require.NoError(t, err)

_, err = client.Logical().Write("transit/keys/leaf", map[string]interface{}{
"type": "rsa-2048",
})
require.NoError(t, err)

resp, err := client.Logical().Read("transit/keys/leaf")
require.NoError(t, err)
require.NotNil(t, resp)

keys := resp.Data["keys"].(map[string]interface{})
require.NotNil(t, keys)
keyData := keys["1"].(map[string]interface{})
require.NotNil(t, keyData)
keyPublic := keyData["public_key"].(string)
require.NotEmpty(t, keyPublic)

pemBlock, _ := pem.Decode([]byte(keyPublic))
require.NotNil(t, pemBlock)
pubKey, err := x509.ParsePKIXPublicKey(pemBlock.Bytes)
require.NoError(t, err)
require.NotNil(t, pubKey)

// Setup a new CSR...
var reqTemplate x509.CertificateRequest
reqTemplate.PublicKey = pubKey
reqTemplate.PublicKeyAlgorithm = x509.RSA
reqTemplate.Subject.CommonName = "dadgarcorp.com"

var k transitKey
k.public = pubKey
k.mount = "transit"
k.name = "leaf"
k.t = t
k.client = client

req, err := x509.CreateCertificateRequest(cryptoRand.Reader, &reqTemplate, &k)
require.NoError(t, err)
require.NotNil(t, req)

reqPEM := pem.EncodeToMemory(&pem.Block{
Type: "CERTIFICATE REQUEST",
Bytes: req,
})
t.Logf("csr: %v", string(reqPEM))

// Mount PKI, generate a root, sign this CSR.
err = client.Sys().Mount("pki", &api.MountInput{
Type: "pki",
})
require.NoError(t, err)

resp, err = client.Logical().Write("pki/root/generate/internal", map[string]interface{}{
"common_name": "PKI Root X1",
})
require.NoError(t, err)
require.NotNil(t, resp)
rootCertPEM := resp.Data["certificate"].(string)

pemBlock, _ = pem.Decode([]byte(rootCertPEM))
require.NotNil(t, pemBlock)

rootCert, err := x509.ParseCertificate(pemBlock.Bytes)
require.NoError(t, err)

resp, err = client.Logical().Write("pki/issuer/default/sign-verbatim", map[string]interface{}{
"csr": string(reqPEM),
"ttl": "10m",
})
require.NoError(t, err)
require.NotNil(t, resp)

leafCertPEM := resp.Data["certificate"].(string)
pemBlock, _ = pem.Decode([]byte(leafCertPEM))
require.NotNil(t, pemBlock)

leafCert, err := x509.ParseCertificate(pemBlock.Bytes)
require.NoError(t, err)
require.NoError(t, leafCert.CheckSignatureFrom(rootCert))
t.Logf("root: %v", rootCertPEM)
t.Logf("leaf: %v", leafCertPEM)
}

0 comments on commit 510f1ab

Please sign in to comment.