github.com/Schaudge/grailbase@v0.0.0-20240223061707-44c758a471c0/security/ticket/tls.go (about)

     1  // Copyright 2018 GRAIL, Inc. All rights reserved.
     2  // Use of this source code is governed by the Apache-2.0
     3  // license that can be found in the LICENSE file.
     4  
     5  package ticket
     6  
     7  import (
     8  	"bytes"
     9  	"crypto/x509"
    10  	"encoding/pem"
    11  	"time"
    12  
    13  	"github.com/Schaudge/grailbase/common/log"
    14  	"github.com/Schaudge/grailbase/security/keycrypt"
    15  	"github.com/Schaudge/grailbase/security/tls/certificateauthority"
    16  )
    17  
    18  const tlsDriftMargin = 10 * time.Minute
    19  
    20  func (b *TlsCertAuthorityBuilder) newTlsClientTicket(ctx *TicketContext) (TicketTlsClientTicket, error) {
    21  	tlsCredentials, err := b.genTlsCredentials(ctx)
    22  
    23  	if err != nil {
    24  		return TicketTlsClientTicket{}, err
    25  	}
    26  
    27  	return TicketTlsClientTicket{
    28  		Value: TlsClientTicket{
    29  			Credentials: tlsCredentials,
    30  		},
    31  	}, nil
    32  }
    33  
    34  func (b *TlsCertAuthorityBuilder) newTlsServerTicket(ctx *TicketContext) (TicketTlsServerTicket, error) {
    35  	tlsCredentials, err := b.genTlsCredentials(ctx)
    36  
    37  	if err != nil {
    38  		return TicketTlsServerTicket{}, err
    39  	}
    40  
    41  	return TicketTlsServerTicket{
    42  		Value: TlsServerTicket{
    43  			Credentials: tlsCredentials,
    44  		},
    45  	}, nil
    46  }
    47  
    48  func (b *TlsCertAuthorityBuilder) newDockerTicket(ctx *TicketContext) (TicketDockerTicket, error) {
    49  	tlsCredentials, err := b.genTlsCredentials(ctx)
    50  
    51  	if err != nil {
    52  		return TicketDockerTicket{}, err
    53  	}
    54  
    55  	return TicketDockerTicket{
    56  		Value: DockerTicket{
    57  			Credentials: tlsCredentials,
    58  		},
    59  	}, nil
    60  }
    61  
    62  func (b *TlsCertAuthorityBuilder) newDockerServerTicket(ctx *TicketContext) (TicketDockerServerTicket, error) {
    63  	tlsCredentials, err := b.genTlsCredentialsWithKeyUsage(ctx, []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth})
    64  
    65  	if err != nil {
    66  		return TicketDockerServerTicket{}, err
    67  	}
    68  
    69  	return TicketDockerServerTicket{
    70  		Value: DockerServerTicket{
    71  			Credentials: tlsCredentials,
    72  		},
    73  	}, nil
    74  }
    75  
    76  func (b *TlsCertAuthorityBuilder) newDockerClientTicket(ctx *TicketContext) (TicketDockerClientTicket, error) {
    77  	tlsCredentials, err := b.genTlsCredentialsWithKeyUsage(ctx, []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth})
    78  
    79  	if err != nil {
    80  		return TicketDockerClientTicket{}, err
    81  	}
    82  
    83  	return TicketDockerClientTicket{
    84  		Value: DockerClientTicket{
    85  			Credentials: tlsCredentials,
    86  		},
    87  	}, nil
    88  }
    89  
    90  func (b *TlsCertAuthorityBuilder) genTlsCredentials(ctx *TicketContext) (TlsCredentials, error) {
    91  	log.Info(ctx.ctx, "Generating TLS credentials.", "TlsCertAuthorityBuilder", b)
    92  	return b.genTlsCredentialsWithKeyUsage(ctx, []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth})
    93  }
    94  
    95  func contains(array []string, entry string) bool {
    96  	for _, e := range array {
    97  		if e == entry {
    98  			return true
    99  		}
   100  	}
   101  
   102  	return false
   103  }
   104  
   105  func (b *TlsCertAuthorityBuilder) genTlsCredentialsWithKeyUsage(ctx *TicketContext, keyUsage []x509.ExtKeyUsage) (TlsCredentials, error) {
   106  	empty := TlsCredentials{}
   107  
   108  	secret, err := keycrypt.Lookup(b.Authority)
   109  	if err != nil {
   110  		return empty, err
   111  	}
   112  	authority := certificateauthority.CertificateAuthority{DriftMargin: tlsDriftMargin, Signer: secret}
   113  	if err := authority.Init(); err != nil {
   114  		return empty, err
   115  	}
   116  	ttl := time.Duration(b.TtlSec) * time.Second
   117  	commonName := b.CommonName
   118  	if commonName == "" {
   119  		commonName = ctx.remoteBlessings.String()
   120  	}
   121  	updatedSan := b.San
   122  	if !contains(updatedSan, commonName) {
   123  		updatedSan = append(updatedSan, commonName)
   124  	}
   125  	cert, key, err := authority.IssueWithKeyUsage(commonName, ttl, nil, updatedSan, keyUsage)
   126  	if err != nil {
   127  		return empty, err
   128  	}
   129  
   130  	r := TlsCredentials{}
   131  	r.AuthorityCert, err = encode(&pem.Block{Type: "CERTIFICATE", Bytes: authority.Cert.Raw})
   132  	if err != nil {
   133  		return empty, err
   134  	}
   135  	r.Cert, err = encode(&pem.Block{Type: "CERTIFICATE", Bytes: cert})
   136  	if err != nil {
   137  		return empty, err
   138  	}
   139  	r.Key, err = encode(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)})
   140  	if err != nil {
   141  		return empty, err
   142  	}
   143  	return r, nil
   144  }
   145  
   146  func encode(block *pem.Block) (string, error) {
   147  	var w bytes.Buffer
   148  	if err := pem.Encode(&w, block); err != nil {
   149  		return "", err
   150  	}
   151  	return w.String(), nil
   152  }