github.com/TykTechnologies/tyk/internal/crypto
No package summary is available.
Package
Files: 6. Third party imports: 3. Imports from organisation: 1. Tests: 0. Benchmarks: 0.
Constants
// `{"` in base64
const B64JSONPrefix = "ey"
const DefaultHashAlgorithm = "murmur64"
const MongoBsonIdLength = 24
const SHA256 = crypto.SHA256
const (
HashSha256 = "sha256"
HashMurmur32 = "murmur32"
HashMurmur64 = "murmur64"
HashMurmur128 = "murmur128"
)
const (
rsaPrivateKey = "RSA PRIVATE KEY"
certificate = "CERTIFICATE"
)
Vars
var (
ErrCertExpired = errors.New("Certificate has expired")
)
var certSubject = pkix.Name{
Organization: []string{"Tyk Technologies Ltd"},
Country: []string{"UK"},
Province: []string{"London"},
Locality: []string{"London"},
StreetAddress: []string{"Worship Street"},
}
Types
CipherSuite
CipherSuite stores information about a cipher suite. It shadows tls.CipherSuite but translates TLS versions to strings.
| Field name | Field type | Comment |
|---|---|---|
| ID |
|
No comment on field. |
| Name |
|
No comment on field. |
| Insecure |
|
No comment on field. |
| TLS |
|
No comment on field. |
type CipherSuite struct {
ID uint16 `json:"id"`
Name string `json:"name"`
Insecure bool `json:"insecure"`
TLS []string `json:"tls"`
}
Hash
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| type |
|
No comment on field. |
type Hash = crypto.Hash
Functions
func Decrypt
Decrypt from base64 to decrypted string
func Decrypt(key []byte, cryptoText string) string {
ciphertext, err := base64.URLEncoding.DecodeString(cryptoText)
if err != nil {
logrus.Error(err)
return ""
}
block, err := aes.NewCipher(key)
if err != nil {
logrus.Error(err)
return ""
}
// The IV needs to be unique, but not secure. Therefore it's common to
// include it at the beginning of the ciphertext.
if len(ciphertext) < aes.BlockSize {
logrus.Error("ciphertext too short")
return ""
}
iv := ciphertext[:aes.BlockSize]
ciphertext = ciphertext[aes.BlockSize:]
stream := cipher.NewCFBDecrypter(block, iv)
// XORKeyStream can work in-place if the two arguments are the same.
stream.XORKeyStream(ciphertext, ciphertext)
return string(ciphertext)
}
Cognitive complexity: 6, Cyclomatic complexity: 4
func Encrypt
encrypt string to base64 crypto using AES
func Encrypt(key []byte, str string) string {
plaintext := []byte(str)
block, err := aes.NewCipher(key)
if err != nil {
logrus.Error(err)
return ""
}
// The IV needs to be unique, but not secure. Therefore, it's common to
// include it at the beginning of the ciphertext.
ciphertext := make([]byte, aes.BlockSize+len(plaintext))
iv := ciphertext[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
logrus.Error(err)
return ""
}
stream := cipher.NewCFBEncrypter(block, iv)
stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)
// convert to base64
return base64.URLEncoding.EncodeToString(ciphertext)
}
Cognitive complexity: 4, Cyclomatic complexity: 3
func GenCertificate
GenCertificate generates a self-signed X.509 certificate based on the provided template. It returns the certificate, private key, combined PEM bytes, and a tls.Certificate.
The function generates a private key, sets the certificate fields if not already set, and creates the certificate in PEM format. Use NotBefore and NotAfter in template to control the certificate expiry. If the NotBefore field of the template is zero-valued, it is set to the current time. If the NotAfter field is zero-valued, it is set to one hour after the NotBefore time. The generated certificate is then encoded to PEM format along with the private key.
A tls.Certificate is created using the PEM-encoded certificate and private key. If setLeaf is true, the certificate's Leaf field is set to the template.
func GenCertificate(template *x509.Certificate, setLeaf bool) ([]byte, []byte, []byte, tls.Certificate) {
priv, _ := rsa.GenerateKey(rand.Reader, 2048)
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, _ := rand.Int(rand.Reader, serialNumberLimit)
template.SerialNumber = serialNumber
template.BasicConstraintsValid = true
if template.NotBefore.IsZero() {
template.NotBefore = time.Now()
}
if template.NotAfter.IsZero() {
template.NotAfter = template.NotBefore.Add(time.Hour)
}
derBytes, _ := x509.CreateCertificate(rand.Reader, template, template, &priv.PublicKey, priv)
var certPem, keyPem bytes.Buffer
pem.Encode(&certPem, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
pem.Encode(&keyPem, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})
clientCert, _ := tls.X509KeyPair(certPem.Bytes(), keyPem.Bytes())
if setLeaf {
clientCert.Leaf = template
}
combinedPEM := bytes.Join([][]byte{certPem.Bytes(), keyPem.Bytes()}, []byte("\n"))
return certPem.Bytes(), keyPem.Bytes(), combinedPEM, clientCert
}
Cognitive complexity: 9, Cyclomatic complexity: 4
func GenServerCertificate
GenServerCertificate generates a self-signed server certificate for "localhost" with DNS names "localhost" and IP addresses 127.0.0.1 and ::. It returns the certificate, private key, combined PEM bytes, and a tls.Certificate.
func GenServerCertificate() ([]byte, []byte, []byte, tls.Certificate) {
certPem, privPem, combinedPEM, cert := GenCertificate(&x509.Certificate{
DNSNames: []string{"localhost"},
IPAddresses: []net.IP{net.ParseIP("127.0.0.1"), net.ParseIP("::")},
}, false)
return certPem, privPem, combinedPEM, cert
}
Cognitive complexity: 3, Cyclomatic complexity: 1
func GenerateClientCertAndKeyChain
GenerateClientCertAndKeyChain generates a client certificate and private key signed by the given root certificate and key, and includes the root certificate in the chain for testing purposes. It returns the client certificate chain and private key in PEM format along with an error, if any.
Parameters:
- tb: The testing.TB instance to log errors and fail the test if necessary.
- rootCertPEM: The root certificate in PEM format.
- rootKeyPEM: The root private key in PEM format.
Returns:
- *bytes.Buffer: The client certificate chain in PEM format.
- *bytes.Buffer: The client private key in PEM format.
- error: Any error encountered during the generation.
func GenerateClientCertAndKeyChain(tb testing.TB, rootCertPEM, rootKeyPEM []byte) (*bytes.Buffer, *bytes.Buffer, error) {
tb.Helper()
clientCertPEM, clientKeyPEM, err := GenerateClientCertAndKeyPEM(tb, rootCertPEM, rootKeyPEM)
assert.NoError(tb, err)
// Include the root certificate in the client certificate chain
_, _ = clientCertPEM.Write(rootCertPEM)
return clientCertPEM, clientKeyPEM, nil
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func GenerateClientCertAndKeyPEM
GenerateClientCertAndKeyPEM generates a client certificate and private key signed by the given root certificate and key for testing purposes. It returns the client certificate and private key in PEM format along with an error, if any.
Parameters:
- tb: The testing.TB instance to log errors and fail the test if necessary.
- rootCertPEM: The root certificate in PEM format.
- rootKeyPEM: The root private key in PEM format.
Returns:
- *bytes.Buffer: The client certificate in PEM format.
- *bytes.Buffer: The client private key in PEM format.
- error: Any error encountered during the generation.
func GenerateClientCertAndKeyPEM(tb testing.TB, rootCertPEM, rootKeyPEM []byte) (*bytes.Buffer, *bytes.Buffer, error) {
tb.Helper()
rootCert, rootKey, err := decodeRootCertAndKey(rootCertPEM, rootKeyPEM)
assert.NoError(tb, err)
// Generate RSA key pair for the client
clientKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return nil, nil, err
}
// Create a template for the client certificate
clientCertTemplate := x509.Certificate{
SerialNumber: big.NewInt(3),
Subject: certSubject,
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(1, 0, 0), // 1 year
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
}
// Create the client certificate signed by the root CA
clientCertDER, err := x509.CreateCertificate(rand.Reader, &clientCertTemplate, rootCert, &clientKey.PublicKey, rootKey)
if err != nil {
return nil, nil, err
}
// Encode the client certificate to PEM format
var clientCertPEM bytes.Buffer
assert.NoError(tb, pem.Encode(&clientCertPEM, &pem.Block{Type: certificate, Bytes: clientCertDER}))
// Encode the client private key to PEM format
var clientKeyPEM bytes.Buffer
assert.NoError(tb, pem.Encode(&clientKeyPEM, &pem.Block{Type: rsaPrivateKey, Bytes: x509.MarshalPKCS1PrivateKey(clientKey)}))
return &clientCertPEM, &clientKeyPEM, nil
}
Cognitive complexity: 8, Cyclomatic complexity: 3
func GenerateRSAPublicKey
GenerateRSAPublicKey generates an RSA public key.
func GenerateRSAPublicKey(tb testing.TB) []byte {
tb.Helper()
// Generate a private key.
priv, err := rsa.GenerateKey(rand.Reader, 2048)
assert.NoError(tb, err)
// Derive the public key from the private key.
publicKey := &priv.PublicKey
// Save the public key in PEM format.
publicKeyBytes, err := x509.MarshalPKIXPublicKey(publicKey)
assert.NoError(tb, err)
publicKeyBlock := &pem.Block{
Type: "PUBLIC KEY",
Bytes: publicKeyBytes,
}
publicKeyPEM := pem.EncodeToMemory(publicKeyBlock)
return publicKeyPEM
}
Cognitive complexity: 1, Cyclomatic complexity: 1
func GenerateRootCertAndKey
GenerateRootCertAndKey generates a root certificate and private key for testing purposes. It returns the root certificate and private key in PEM format along with an error, if any.
Parameters:
- tb: The testing.TB instance to log errors and fail the test if necessary.
Returns:
- []byte: The root certificate in PEM format.
- []byte: The root private key in PEM format.
- error: Any error encountered during the generation.
func GenerateRootCertAndKey(tb testing.TB) ([]byte, []byte, error) {
tb.Helper()
// Generate RSA key pair
rootKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return nil, nil, err
}
// Create a template for the root certificate
rootCertTemplate := x509.Certificate{
SerialNumber: big.NewInt(1),
Subject: certSubject,
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(10, 0, 0), // 10 years
KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
BasicConstraintsValid: true,
IsCA: true,
}
// Create the root certificate
rootCertDER, err := x509.CreateCertificate(rand.Reader, &rootCertTemplate, &rootCertTemplate, &rootKey.PublicKey, rootKey)
if err != nil {
return nil, nil, err
}
// Encode the root certificate to PEM format
var rootCertPEM bytes.Buffer
assert.NoError(tb, pem.Encode(&rootCertPEM, &pem.Block{Type: certificate, Bytes: rootCertDER}))
// Encode the root private key to PEM format
var rootKeyPEM bytes.Buffer
assert.NoError(tb, pem.Encode(&rootKeyPEM, &pem.Block{Type: rsaPrivateKey, Bytes: x509.MarshalPKCS1PrivateKey(rootKey)}))
return rootCertPEM.Bytes(), rootKeyPEM.Bytes(), nil
}
Cognitive complexity: 7, Cyclomatic complexity: 3
func GenerateServerCertAndKeyChain
GenerateServerCertAndKeyChain generates a server certificate and private key signed by the given root certificate and key, and includes the root certificate in the chain for testing purposes. It returns the server certificate chain and private key in PEM format along with an error, if any.
Parameters:
- tb: The testing.TB instance to log errors and fail the test if necessary.
- rootCertPEM: The root certificate in PEM format.
- rootKeyPEM: The root private key in PEM format.
Returns:
- *bytes.Buffer: The server certificate chain in PEM format.
- *bytes.Buffer: The server private key in PEM format.
- error: Any error encountered during the generation.
func GenerateServerCertAndKeyChain(tb testing.TB, rootCertPEM, rootKeyPEM []byte) (*bytes.Buffer, *bytes.Buffer, error) {
tb.Helper()
serverCertPEM, serverKeyPEM, err := GenerateServerCertAndKeyPEM(tb, rootCertPEM, rootKeyPEM)
assert.NoError(tb, err)
// Include the root certificate in the client certificate chain
_, _ = serverCertPEM.Write(rootCertPEM)
return serverCertPEM, serverKeyPEM, nil
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func GenerateServerCertAndKeyPEM
GenerateServerCertAndKeyPEM generates a server certificate and private key signed by the given root certificate and key for testing purposes. It returns the server certificate and private key in PEM format along with an error, if any.
Parameters:
- tb: The testing.TB instance to log errors and fail the test if necessary.
- rootCertPEM: The root certificate in PEM format.
- rootKeyPEM: The root private key in PEM format.
Returns:
- *bytes.Buffer: The server certificate in PEM format.
- *bytes.Buffer: The server private key in PEM format.
- error: Any error encountered during the generation.
func GenerateServerCertAndKeyPEM(tb testing.TB, rootCertPEM, rootKeyPEM []byte) (*bytes.Buffer, *bytes.Buffer, error) {
tb.Helper()
rootCert, rootKey, err := decodeRootCertAndKey(rootCertPEM, rootKeyPEM)
assert.NoError(tb, err)
// Generate RSA key pair for the server
serverKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return nil, nil, err
}
// Create a template for the server certificate
serverCertTemplate := x509.Certificate{
SerialNumber: big.NewInt(2),
Subject: certSubject,
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(1, 0, 0), // 1 year
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
IPAddresses: []net.IP{net.ParseIP("127.0.0.1")},
DNSNames: []string{"localhost"},
}
// Create the server certificate signed by the root CA
serverCertDER, err := x509.CreateCertificate(rand.Reader, &serverCertTemplate, rootCert, &serverKey.PublicKey, rootKey)
if err != nil {
return nil, nil, err
}
// Encode the server certificate to PEM format
var serverCertPEM bytes.Buffer
assert.NoError(tb, pem.Encode(&serverCertPEM, &pem.Block{Type: certificate, Bytes: serverCertDER}))
// Encode the server private key to PEM format
var serverKeyPEM bytes.Buffer
assert.NoError(tb, pem.Encode(&serverKeyPEM, &pem.Block{Type: rsaPrivateKey, Bytes: x509.MarshalPKCS1PrivateKey(serverKey)}))
return &serverCertPEM, &serverKeyPEM, nil
}
Cognitive complexity: 10, Cyclomatic complexity: 3
func GenerateToken
GenerateToken generates a token. If hashing algorithm is empty, it uses legacy key generation.
func GenerateToken(orgID, keyID, hashAlgorithm string) (string, error) {
if keyID == "" {
keyID = uuid.NewHex()
}
if hashAlgorithm != "" {
_, err := hashFunction(hashAlgorithm)
if err != nil {
hashAlgorithm = DefaultHashAlgorithm
}
jsonToken := fmt.Sprintf(`{"org":"%s","id":"%s","h":"%s"}`, orgID, keyID, hashAlgorithm)
return base64.StdEncoding.EncodeToString([]byte(jsonToken)), err
}
// Legacy keys
return orgID + keyID, nil
}
Cognitive complexity: 7, Cyclomatic complexity: 4
func GetCiphers
GetCiphers generates a list of CipherSuite from the available ciphers.
func GetCiphers() []*CipherSuite {
ciphers := tls.CipherSuites()
result := make([]*CipherSuite, 0, len(ciphers))
for _, cipher := range ciphers {
result = append(result, NewCipher(cipher))
}
return result
}
Cognitive complexity: 3, Cyclomatic complexity: 2
func GetPaddedString
func GetPaddedString(str string) []byte {
return []byte(RightPad2Len(str, "=", 32))
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func HashKey
func HashKey(in string, hashKey bool) string {
if !hashKey {
// Not hashing? Return the raw key
return in
}
return HashStr(in)
}
Cognitive complexity: 2, Cyclomatic complexity: 2
func HashStr
func HashStr(in string, withAlg ...string) string {
var algo string
if len(withAlg) > 0 && withAlg[0] != "" {
algo = withAlg[0]
} else {
algo = TokenHashAlgo(in)
}
h, err := hashFunction(algo)
if err != nil {
logrus.Error(err)
}
h.Write([]byte(in))
return hex.EncodeToString(h.Sum(nil))
}
Cognitive complexity: 6, Cyclomatic complexity: 4
func HexSHA256
HexSHA256 calculates the SHA256 hash of the provided certificate bytes and returns the result as a hexadecimal string.
func HexSHA256(cert []byte) string {
certSHA := sha256.Sum256(cert)
return hex.EncodeToString(certSHA[:])
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func IsPublicKey
IsPublicKey verifies if given certificate is a public key only.
func IsPublicKey(cert *tls.Certificate) bool {
return cert.Leaf != nil && strings.HasPrefix(cert.Leaf.Subject.CommonName, "Public Key: ")
}
Cognitive complexity: 0, Cyclomatic complexity: 2
func NewCipher
NewCipher translates tls.CipherSuite to our local type.
func NewCipher(in *tls.CipherSuite) *CipherSuite {
return &CipherSuite{
ID: in.ID,
Name: in.Name,
Insecure: in.Insecure,
TLS: TLSVersions(in.SupportedVersions),
}
}
Cognitive complexity: 1, Cyclomatic complexity: 1
func PrefixPublicKeyCommonName
PrefixPublicKeyCommonName returns x509.Certificate with prefixed CommonName. This is used in UI/response to hint the type certificate during listing.
func PrefixPublicKeyCommonName(blockBytes []byte) *x509.Certificate {
return &x509.Certificate{
Subject: pkix.Name{
CommonName: "Public Key: " + HexSHA256(blockBytes),
},
}
}
Cognitive complexity: 2, Cyclomatic complexity: 1
func ResolveCipher
ResolveCipher translates a string representation of a cipher to its uint16 ID. It's case-insensitive when matching the cipher by name.
func ResolveCipher(cipherName string) (uint16, error) {
ciphers := GetCiphers()
for _, cipher := range ciphers {
if strings.EqualFold(cipher.Name, cipherName) {
return cipher.ID, nil
}
}
return 0, fmt.Errorf("cipher %s not found", cipherName)
}
Cognitive complexity: 5, Cyclomatic complexity: 3
func RightPad2Len
func RightPad2Len(s, padStr string, overallLen int) string {
padCountInt := 1 + (overallLen-len(padStr))/len(padStr)
retStr := s + strings.Repeat(padStr, padCountInt)
return retStr[:overallLen]
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func TLSVersions
TLSVersions will return a list of TLS versions as a string.
func TLSVersions(in []uint16) []string {
versions := make([]string, len(in))
for i, v := range in {
switch v {
case tls.VersionTLS10:
versions[i] = "1.0"
case tls.VersionTLS11:
versions[i] = "1.1"
case tls.VersionTLS12:
versions[i] = "1.2"
case tls.VersionTLS13:
versions[i] = "1.3"
default:
versions[i] = ""
}
}
return versions
}
Cognitive complexity: 9, Cyclomatic complexity: 7
func TokenHashAlgo
func TokenHashAlgo(token string) string {
// Legacy tokens not b64 and not JSON records
if strings.HasPrefix(token, B64JSONPrefix) {
if jsonToken, err := base64.StdEncoding.DecodeString(token); err == nil {
hashAlgo, err := jsonparser.GetString(jsonToken, "h")
if err != nil {
logrus.Error(err)
return ""
}
return hashAlgo
}
}
return ""
}
Cognitive complexity: 6, Cyclomatic complexity: 4
func TokenID
func TokenID(token string) (id string, err error) {
jsonToken, err := base64.StdEncoding.DecodeString(token)
if err != nil {
return "", err
}
return jsonparser.GetString(jsonToken, "id")
}
Cognitive complexity: 2, Cyclomatic complexity: 2
func TokenOrg
func TokenOrg(token string) string {
if strings.HasPrefix(token, B64JSONPrefix) {
if jsonToken, err := base64.StdEncoding.DecodeString(token); err == nil {
// Checking error in case if it is a legacy token which just by accided has the same b64JSON prefix
if org, err := jsonparser.GetString(jsonToken, "org"); err == nil {
return org
}
}
}
// 24 is mongo bson id length
if len(token) > MongoBsonIdLength {
newToken := token[:MongoBsonIdLength]
_, err := hex.DecodeString(newToken)
if err == nil {
return newToken
}
}
return ""
}
Cognitive complexity: 10, Cyclomatic complexity: 6
func ValidateRequestCerts
ValidateRequestCerts validates client TLS certificates against a list of allowed certificates configured in API definition. It returns an error if TLS is not enabled, the client certificate is missing, or if it is not allowed or expired.
func ValidateRequestCerts(r *http.Request, certs []*tls.Certificate) error {
if r.TLS == nil {
return errors.New("TLS not enabled")
}
if len(r.TLS.PeerCertificates) == 0 {
return errors.New("Client TLS certificate is required")
}
// Loop through r.TLS.PeerCertificates to add intermediate CA certificates to the allow list.
for _, peerCertificate := range r.TLS.PeerCertificates {
certID := HexSHA256(peerCertificate.Raw)
for _, cert := range certs {
// In case a cert can't be parsed or is invalid,
// it will be present in the cert list as 'nil'
if cert == nil {
// Invalid cert, continue to next one
continue
}
if cert.Leaf.IsCA && verifyCertAgainstCA(cert, peerCertificate) == nil {
return nil
}
// Extensions[0] contains cache of certificate SHA256
if string(cert.Leaf.Extensions[0].Value) == certID {
if time.Now().After(cert.Leaf.NotAfter) {
return ErrCertExpired
}
// Happy flow, we matched a certificate
return nil
}
}
}
return errors.New("Certificate with SHA256 " + HexSHA256(r.TLS.PeerCertificates[0].Raw) + " not allowed")
}
Cognitive complexity: 18, Cyclomatic complexity: 10
func (*CipherSuite) String
String returns a human-readable string for the cipher.
func (c *CipherSuite) String() string {
return fmt.Sprintf("Cipher ID: %d, Name: %s, Insecure: %t, TLS: %v", c.ID, c.Name, c.Insecure, c.TLS)
}
Cognitive complexity: 0, Cyclomatic complexity: 1
Private functions
func decodeRootCertAndKey
decodeRootCertAndKey (rootCertPEM,rootKeyPEM []byte) (*x509.Certificate, *rsa.PrivateKey, error)
References: fmt.Errorf, pem.Decode, x509.ParseCertificate, x509.ParsePKCS1PrivateKey.
func hashFunction
hashFunction (algorithm string) (hash.Hash, error)
References: fmt.Errorf, murmur3.New128, murmur3.New32, murmur3.New64, sha256.New.
func verifyCertAgainstCA
verifyCertAgainstCA (caCert *tls.Certificate, peerCert *x509.Certificate) error
References: x509.NewCertPool, x509.VerifyOptions.
Tests
Files: 2. Third party imports: 1. Imports from organisation: 0. Tests: 6. Benchmarks: 0.