github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/tools/lxdclient/cert.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 // +build go1.3 5 6 package lxdclient 7 8 import ( 9 "crypto/sha256" 10 "crypto/x509" 11 "encoding/pem" 12 "fmt" 13 "io" 14 15 "github.com/juju/errors" 16 ) 17 18 const ( 19 certDefaultName = "juju-client-certificate" 20 ) 21 22 // Cert holds the information for a single certificate a client 23 // may use to connect to a remote server. 24 type Cert struct { 25 // Name is the name that LXD will use for the cert. 26 Name string 27 28 // CertPEM is the PEM-encoded x.509 cert. 29 CertPEM []byte 30 31 // KeyPEM is the PEM-encoded x.509 private key. 32 KeyPEM []byte 33 } 34 35 // NewCertificate creates a new Certificate for the given cert and key. 36 func NewCert(certPEM, keyPEM []byte) Cert { 37 return Cert{ 38 CertPEM: certPEM, 39 KeyPEM: keyPEM, 40 } 41 } 42 43 // WithDefaults updates a copy of the remote with default values 44 // where needed. 45 func (cert Cert) WithDefaults() (Cert, error) { 46 // Note that cert is a value receiver, so it is an implicit copy. 47 48 if cert.Name == "" { 49 // The certificate Name will get overridden later by code that 50 // knows what environment this certificate is being used for. 51 cert.Name = certDefaultName 52 } 53 54 // WithDefaults doesn't populate CertPEM or KeyPEM because those aren't 55 // used when contacting the LXD service via the unix socket. 56 return cert, nil 57 } 58 59 // Validate ensures that the cert is valid. 60 func (cert Cert) Validate() error { 61 if len(cert.CertPEM) == 0 { 62 return errors.NotValidf("missing cert PEM") 63 } 64 if len(cert.KeyPEM) == 0 { 65 return errors.NotValidf("missing key PEM") 66 } 67 68 // TODO(ericsnow) Ensure cert and key are valid? 69 70 return nil 71 } 72 73 // WriteCertPEM writes the cert's x.509 PEM data to the given writer. 74 func (cert Cert) WriteCertPEM(out io.Writer) error { 75 if _, err := out.Write(cert.CertPEM); err != nil { 76 return errors.Trace(err) 77 } 78 return nil 79 } 80 81 // WriteKeytPEM writes the key's x.509 PEM data to the given writer. 82 func (cert Cert) WriteKeyPEM(out io.Writer) error { 83 if _, err := out.Write(cert.KeyPEM); err != nil { 84 return errors.Trace(err) 85 } 86 return nil 87 } 88 89 // Fingerprint returns the cert's LXD fingerprint. 90 func (cert Cert) Fingerprint() (string, error) { 91 // See: https://github.com/lxc/lxd/blob/master/lxd/certificates.go 92 x509Cert, err := cert.X509() 93 if err != nil { 94 return "", errors.Trace(err) 95 } 96 data := sha256.Sum256(x509Cert.Raw) 97 return fmt.Sprintf("%x", data), nil 98 } 99 100 // X509 returns the x.509 certificate. 101 func (cert Cert) X509() (*x509.Certificate, error) { 102 block, _ := pem.Decode(cert.CertPEM) 103 if block == nil { 104 return nil, errors.Errorf("invalid cert PEM (%d bytes)", len(cert.CertPEM)) 105 } 106 107 x509Cert, err := x509.ParseCertificate(block.Bytes) 108 if err != nil { 109 return nil, errors.Trace(err) 110 } 111 112 return x509Cert, nil 113 }