Skip to content

Instantly share code, notes, and snippets.

@salrashid123
Last active November 20, 2024 23:56
Show Gist options
  • Save salrashid123/443beb8992482f60cd9411d44b0a6fe2 to your computer and use it in GitHub Desktop.
Save salrashid123/443beb8992482f60cd9411d44b0a6fe2 to your computer and use it in GitHub Desktop.
GCP Enterprise Cert Proxy with SoftHSM

GCP Enterprise Certificate Proxy with SoftHSM

setup of Google Proxies for Enterprise Certificates (GA) with SoftHSM

This sample will embed a device certificate and key into SoftHSM and then access softHSM for mTLS using the GCP proxy.

A default GCS client uses the enterprise proxy transparently to access gcp resources via mTLS


First step is to setup device certificates. This isn't covered in this repo but just assume

the keypair user10.crt, user10.key represents a user's device cert provisioned by an admin

Initialize softhsm

mkdir /tmp/softhsm_tokens

create file /tmp/softhsm.conf with

log.level = DEBUG
objectstore.backend = file
directories.tokendir = /tmp/softhsm_tokens
slots.removable = true

import the certs

sudo apt-get install softhsm opensc

export SOFTHSM2_CONF=/tmp/softhsm.conf
pkcs11-tool --module /usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so --list-mechanisms --slot-index 0

pkcs11-tool --module /usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so --slot-index=0 --init-token --label="token1" --so-pin="123456"
pkcs11-tool --module /usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so  --label="token1" --init-pin --so-pin "123456" --pin mynewpin
pkcs11-tool --module /usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so --slot-index=0 --init-token --label="token1" --so-pin="123456"
pkcs11-tool --module /usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so  --label="token1" --init-pin --so-pin "123456" --pin mynewpin

### convert to der
openssl x509 -in user10.crt -out sts.crt.der -outform DER 
openssl rsa -inform pem -in user10.key -outform der -out sts.key.der
openssl x509 -pubkey -noout -in user10.crt  > user10pub.pem
openssl rsa -pubin -inform PEM -in user10pub.pem -outform DER -out user10pub.der

# import key and cert
pkcs11-tool  --module /usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so --pin mynewpin \
   --write-object sts.crt.der --type cert --id 10 --label keylabel3 --slot-index 0

pkcs11-tool  --module /usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so --pin mynewpin \
   --write-object sts.key.der --type privkey --id 10 --label keylabel3 --slot-index 0

pkcs11-tool  --module /usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so --pin mynewpin \
   --write-object user10pub.der --type pubkey --id 10 --label keylabel3 --slot-index 0

print the token and slots

$ pkcs11-tool --module /usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so --list-token-slots
Available slots:
Slot 0 (0x51aac4a2): SoftHSM slot ID 0x51aac4a2
  token label        : token1
  token manufacturer : SoftHSM project
  token model        : SoftHSM v2
  token flags        : login required, rng, token initialized, PIN initialized, other flags=0x20
  hardware version   : 2.6
  firmware version   : 2.6
  serial num         : 7b07faced1aac4a2
  pin min/max        : 4/255
Slot 1 (0x1): SoftHSM slot ID 0x1
  token state:   uninitialized


$ pkcs11-tool --module /usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so  --list-objects --pin mynewpin
Using slot 0 with a present token (0x51aac4a2)
Public Key Object; RSA 2048 bits
  label:      keylabel3
  ID:         10
  Usage:      encrypt, verify, wrap
  Access:     none
Private Key Object; RSA 
  label:      keylabel3
  ID:         10
  Usage:      decrypt, sign, unwrap
  Access:     sensitive
Certificate Object; type = X.509 cert
  label:      keylabel3
  subject:    DN: L=US, O=Google, OU=Enterprise, CN=user10.esodemoapp2.com
  serial:     1C
  ID:         10

create sdk config file api_cert_config.config note the slot below..your value will be different. you can find it with the command above

{
    "cert_configs": {
      "pkcs11": {
        "label": "keylabel3",
        "user_pin": "mynewpin",
        "slot": "0x51aac4a2",
        "module": "/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so"
      }
    },
    "libs": {
        "ecp": "/usr/lib/google-cloud-sdk/bin/ecp",
        "ecp_client": "/usr/lib/google-cloud-sdk/platform/enterprise_cert/libecp.so",
        "tls_offload": "/usr/lib/google-cloud-sdk/platform/enterprise_cert/libtls_offload.so"
    },
    "version": 1
  }

install enterprise proxy

gcloud components install enterprise-certificate-proxy

export GOOGLE_API_USE_CLIENT_CERTIFICATE=true
export GOOGLE_API_CERTIFICATE_CONFIG=/path/to/api_cert_config.json
export ENABLE_ENTERPRISE_CERTIFICATE_LOGS=1
export SOFTHSM2_CONF=/tmp/softhsm.conf

Now run any gcs client as is

package main

import (
	"context"
	"fmt"
	"io"
	"os"

	"cloud.google.com/go/storage"
)

const (
	projectID  = "your-project"
	bucketName = "your-bucket"
	objectName = "foo.txt"
)

func main() {

	ctx := context.Background()

	storageClient, err := storage.NewClient(ctx)
	if err != nil {
		fmt.Printf("%v", err)
		os.Exit(1)
	}
	defer storageClient.Close()

	bkt := storageClient.Bucket(bucketName)
	obj := bkt.Object(objectName)

	rdr, err := obj.NewReader(ctx)
	if err != nil {
		fmt.Printf("%v", err)
		os.Exit(1)
	}
	_, err = io.Copy(os.Stdout, rdr)
	if err = rdr.Close(); err != nil {
		fmt.Println(err)
	}
	fmt.Println()

}

Chrome NSS

see chromium cert_management

$ export SOFTHSM2_CONF=/tmp/softhsm.conf
$ modutil -dbdir sql:.pki/nssdb/ -list

$ modutil -dbdir sql:.pki/nssdb/ -add "SoftHSM PKCS#11" -libfile /usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so

$ modutil -dbdir sql:.pki/nssdb/ -list

Listing of PKCS #11 Modules
-----------------------------------------------------------
  1. NSS Internal PKCS #11 Module
     uri: pkcs11:library-manufacturer=Mozilla%20Foundation;library-description=NSS%20Internal%20Crypto%20Services;library-version=3.87
   slots: 2 slots attached
  status: loaded

   slot: NSS Internal Cryptographic Services
  token: NSS Generic Crypto Services
    uri: pkcs11:token=NSS%20Generic%20Crypto%20Services;manufacturer=Mozilla%20Foundation;serial=0000000000000000;model=NSS%203

   slot: NSS User Private Key and Certificate Services
  token: NSS Certificate DB
    uri: pkcs11:token=NSS%20Certificate%20DB;manufacturer=Mozilla%20Foundation;serial=0000000000000000;model=NSS%203

  2. OpenSC smartcard framework (0.23)
  library name: /usr/lib/x86_64-linux-gnu/onepin-opensc-pkcs11.so
     uri: pkcs11:library-manufacturer=OpenSC%20Project;library-description=OpenSC%20smartcard%20framework;library-version=0.23
   slots: There are no slots attached to this module
  status: loaded

  3. SoftHSM PKCS#11
  library name: /usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so
     uri: pkcs11:library-manufacturer=SoftHSM;library-description=Implementation%20of%20PKCS11;library-version=2.6
   slots: 2 slots attached
  status: loaded

   slot: SoftHSM slot ID 0x51aac4a2
  token: token1
    uri: pkcs11:token=token1;manufacturer=SoftHSM%20project;serial=7b07faced1aac4a2;model=SoftHSM%20v2

   slot: SoftHSM slot ID 0x1
  token: 
    uri: pkcs11:manufacturer=SoftHSM%20project;model=SoftHSM%20v2

then set the SOFTHSM2_CONF env var and launch chrome

export SOFTHSM2_CONF=/tmp/softhsm.conf
/opt/google/chrome/chrome

Manual TLS

if you'd rather not use the enterprise proxy and instead do this all by hand,

package main

import (
    "context"
    "crypto/tls"
    "fmt"
    "io"
    "log"
    "net/http"
    "os"

    "cloud.google.com/go/storage"
    "github.com/ThalesIgnite/crypto11"
    salpkcs "github.com/salrashid123/mtls_pkcs11/signer/pkcs"
    "golang.org/x/oauth2"
    "golang.org/x/oauth2/google"
    "google.golang.org/api/option"
)

const (
    projectID  = "core-eso"
    bucketName = "core-eso-bucket"
    objectName = "foo.txt"
)

func main() {

    ctx := context.Background()

    // export GOOGLE_API_USE_CLIENT_CERTIFICATE=true
    // export SOFTHSM2_CONF=`pwd`/softhsm.conf
    // softhsm
    // export SOFTHSM2_CONF=/home/srashid/Desktop/misc/soft_hsm/softhsm.conf

    // var slotNum *int
    // slotNum = new(int)
    // *slotNum = 1370145954 // 0x51aac4a2

    config := &crypto11.Config{
        Path:       "/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so",
        TokenLabel: "token1",
        Pin:        "mynewpin",
        //SlotNumber: slotNum,
    }

    pctx, err := crypto11.Configure(config)
    if err != nil {
        log.Fatal(err)
    }

    defer pctx.Close()

    r, err := salpkcs.NewPKCSCrypto(&salpkcs.PKCS{
        Context:        pctx,
        PkcsId:         nil,                 //softhsm
        PkcsLabel:      []byte("keylabel3"), //softhsm
        PublicCertFile: "user10.crt",        //softhsm

    })
    if err != nil {
        log.Fatal(err)
    }

    //cert, err := tls.LoadX509KeyPair("user10.crt", "user10.key")

    if err != nil {
        log.Fatalf("failed to load root CA certificates  error=%v", err)
    }
    tt := &tls.Config{
        //Certificates: []tls.Certificate{cert},
        Certificates: []tls.Certificate{r.TLSCertificate()},
    }

    sslKeyLogfile := os.Getenv("SSLKEYLOGFILE")
    if sslKeyLogfile != "" {
        var w *os.File
        w, err := os.OpenFile(sslKeyLogfile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0600)
        if err != nil {
            fmt.Printf("Could not create keylogger: ", err)
            return
        }
        tt.KeyLogWriter = w
    }

    tr := &http.Transport{
        TLSClientConfig: tt,
    }

    ts, err := google.DefaultTokenSource(ctx)
    if err != nil {
        fmt.Printf("%v", err)
        os.Exit(1)
    }

    client := &http.Client{
        Transport: &oauth2.Transport{
            Base:   tr,
            Source: ts,
        },
    }


    storageClient, err := storage.NewClient(ctx, option.WithHTTPClient(client))
    if err != nil {
        fmt.Printf("%v", err)
        os.Exit(1)
    }
    defer storageClient.Close()

    bkt := storageClient.Bucket(bucketName)
    obj := bkt.Object(objectName)

    rdr, err := obj.NewReader(ctx)
    if err != nil {
        fmt.Printf("%v", err)
        os.Exit(1)
    }
    _, err = io.Copy(os.Stdout, rdr)
    if err != nil {
        fmt.Printf("%v", err)
        os.Exit(1)
    }
    if err = rdr.Close(); err != nil {
        fmt.Println(err)
    }
    fmt.Println()

}
@salrashid123
Copy link
Author

salrashid123 commented Nov 14, 2024

access_level

device_cert

vpc_sc

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment