...

Source file src/github.com/googleapis/enterprise-certificate-proxy/cshared/main.go

Documentation: github.com/googleapis/enterprise-certificate-proxy/cshared

     1  // Copyright 2022 Google LLC.
     2  // Licensed under the Apache License, Version 2.0 (the "License");
     3  // you may not use this file except in compliance with the License.
     4  // You may obtain a copy of the License at
     5  //
     6  //     https://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  // This package is intended to be compiled into a C shared library for
    15  // use by non-Golang clients to perform certificate and signing operations.
    16  //
    17  // The shared library exports language-specific wrappers around the Golang
    18  // client APIs.
    19  //
    20  // Example compilation command:
    21  // go build -buildmode=c-shared -o signer.dylib main.go
    22  package main
    23  
    24  /*
    25  #include <stdlib.h>
    26  */
    27  import "C"
    28  
    29  import (
    30  	"crypto"
    31  	"crypto/ecdsa"
    32  	"crypto/rsa"
    33  	"encoding/pem"
    34  	"io"
    35  	"log"
    36  	"os"
    37  	"unsafe"
    38  
    39  	"github.com/googleapis/enterprise-certificate-proxy/client"
    40  )
    41  
    42  // If ECP Logging is enabled return true
    43  // Otherwise return false
    44  func enableECPLogging() bool {
    45  	if os.Getenv("ENABLE_ENTERPRISE_CERTIFICATE_LOGS") != "" {
    46  		return true
    47  	}
    48  
    49  	log.SetOutput(io.Discard)
    50  	return false
    51  }
    52  
    53  func getCertPem(configFilePath string) []byte {
    54  	key, err := client.Cred(configFilePath)
    55  	if err != nil {
    56  		log.Printf("Could not create client using config %s: %v", configFilePath, err)
    57  		return nil
    58  	}
    59  	defer func() {
    60  		if err = key.Close(); err != nil {
    61  			log.Printf("Failed to clean up key. %v", err)
    62  		}
    63  	}()
    64  
    65  	certChain := key.CertificateChain()
    66  	certChainPem := []byte{}
    67  	for i := 0; i < len(certChain); i++ {
    68  		certPem := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certChain[i]})
    69  		certChainPem = append(certChainPem, certPem...)
    70  	}
    71  	return certChainPem
    72  }
    73  
    74  // GetCertPemForPython reads the contents of the certificate specified by configFilePath,
    75  // storing the result inside a certHolder byte array of size certHolderLen.
    76  //
    77  // We must call it twice to get the cert. First time use nil for certHolder to get
    78  // the cert length. Second time we pre-create an array in Python of the cert length and
    79  // call this function again to load the cert into the array.
    80  //
    81  //export GetCertPemForPython
    82  func GetCertPemForPython(configFilePath *C.char, certHolder *byte, certHolderLen int) int {
    83  	enableECPLogging()
    84  	pemBytes := getCertPem(C.GoString(configFilePath))
    85  	if certHolder != nil {
    86  		cert := unsafe.Slice(certHolder, certHolderLen)
    87  		copy(cert, pemBytes)
    88  	}
    89  	return len(pemBytes)
    90  }
    91  
    92  // SignForPython signs a message digest of length digestLen using a certificate private key
    93  // specified by configFilePath, storing the result inside a sigHolder byte array of size sigHolderLen.
    94  //
    95  //export SignForPython
    96  func SignForPython(configFilePath *C.char, digest *byte, digestLen int, sigHolder *byte, sigHolderLen int) int {
    97  	// First create a handle around the specified certificate and private key.
    98  	enableECPLogging()
    99  	key, err := client.Cred(C.GoString(configFilePath))
   100  	if err != nil {
   101  		log.Printf("Could not create client using config %s: %v", C.GoString(configFilePath), err)
   102  		return 0
   103  	}
   104  	defer func() {
   105  		if err = key.Close(); err != nil {
   106  			log.Printf("Failed to clean up key. %v", err)
   107  		}
   108  	}()
   109  	var isRsa bool
   110  	switch key.Public().(type) {
   111  	case *ecdsa.PublicKey:
   112  		isRsa = false
   113  		log.Print("the key is ecdsa key")
   114  	case *rsa.PublicKey:
   115  		isRsa = true
   116  		log.Print("the key is rsa key")
   117  	default:
   118  		log.Printf("unsupported key type")
   119  		return 0
   120  	}
   121  
   122  	// Compute the signature
   123  	digestSlice := unsafe.Slice(digest, digestLen)
   124  	var signature []byte
   125  	var signErr error
   126  	if isRsa {
   127  		// For RSA key, we need to create the padding and flags for RSASSA-SHA256
   128  		opts := rsa.PSSOptions{
   129  			SaltLength: digestLen,
   130  			Hash:       crypto.SHA256,
   131  		}
   132  
   133  		signature, signErr = key.Sign(nil, digestSlice, &opts)
   134  	} else {
   135  		signature, signErr = key.Sign(nil, digestSlice, crypto.SHA256)
   136  	}
   137  	if signErr != nil {
   138  		log.Printf("failed to sign hash: %v", signErr)
   139  		return 0
   140  	}
   141  	if sigHolderLen < len(signature) {
   142  		log.Printf("The sigHolder buffer size %d is smaller than the signature size %d", sigHolderLen, len(signature))
   143  		return 0
   144  	}
   145  
   146  	// Create a Go buffer around the output buffer and copy the signature into the buffer
   147  	outBytes := unsafe.Slice(sigHolder, sigHolderLen)
   148  	copy(outBytes, signature)
   149  	return len(signature)
   150  }
   151  
   152  // GetKeyType returns a string representing ECP's key type.
   153  // The key is derived from the ECP configuration.
   154  //
   155  //export GetKeyType
   156  func GetKeyType(configFilePath *C.char) *C.char {
   157  	key, err := client.Cred(C.GoString(configFilePath))
   158  	if err != nil {
   159  		log.Printf("Could not create client using config %s: %v", C.GoString(configFilePath), err)
   160  		return C.CString("unknown")
   161  	}
   162  	defer func() {
   163  		if err = key.Close(); err != nil {
   164  			log.Printf("Failed to clean up key. %v", err)
   165  		}
   166  	}()
   167  	switch key.Public().(type) {
   168  	case *ecdsa.PublicKey:
   169  		return C.CString("EC")
   170  	case *rsa.PublicKey:
   171  		return C.CString("RSA")
   172  	default:
   173  		return C.CString("unknown")
   174  	}
   175  }
   176  
   177  func main() {}
   178  

View as plain text