func makeSigningKeyWithChain(rootKey libtrust.PrivateKey, depth int) (libtrust.PrivateKey, error) { if depth == 0 { // Don't need to build a chain. return rootKey, nil } var ( x5c = make([]string, depth) parentKey = rootKey key libtrust.PrivateKey cert *x509.Certificate err error ) for depth > 0 { if key, err = libtrust.GenerateECP256PrivateKey(); err != nil { return nil, err } if cert, err = libtrust.GenerateCACert(parentKey, key); err != nil { return nil, err } depth-- x5c[depth] = base64.StdEncoding.EncodeToString(cert.Raw) parentKey = key } key.AddExtendedField("x5c", x5c) return key, nil }
// NewIdentityAuthTLSConfig creates a tls.Config for the server to use for // libtrust identity authentication func NewIdentityAuthTLSConfig(trustKey libtrust.PrivateKey, clients *ClientKeyManager, addr string) (*tls.Config, error) { tlsConfig := createTLSConfig() tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert if err := clients.RegisterTLSConfig(tlsConfig); err != nil { return nil, err } // Generate cert ips, domains, err := parseAddr(addr) if err != nil { return nil, err } // add default docker domain for docker clients to look for domains = append(domains, "docker") x509Cert, err := libtrust.GenerateSelfSignedServerCert(trustKey, domains, ips) if err != nil { return nil, fmt.Errorf("certificate generation error: %s", err) } tlsConfig.Certificates = []tls.Certificate{{ Certificate: [][]byte{x509Cert.Raw}, PrivateKey: trustKey.CryptoPrivateKey(), Leaf: x509Cert, }} return tlsConfig, nil }
//make token core func makeTokenCore(issuer, subject, audience string, expiration int, access []*token.ResourceActions, signingKey libtrust.PrivateKey) (t *token.Token, expiresIn int, issuedAt *time.Time, err error) { joseHeader := &token.Header{ Type: "JWT", SigningAlg: "RS256", KeyID: signingKey.KeyID(), } jwtID, err := randString(16) if err != nil { return nil, 0, nil, fmt.Errorf("Error to generate jwt id: %s", err) } now := time.Now().UTC() issuedAt = &now expiresIn = expiration * 60 claimSet := &token.ClaimSet{ Issuer: issuer, Subject: subject, Audience: audience, Expiration: now.Add(time.Duration(expiration) * time.Minute).Unix(), NotBefore: now.Unix(), IssuedAt: now.Unix(), JWTID: jwtID, Access: access, } var joseHeaderBytes, claimSetBytes []byte if joseHeaderBytes, err = json.Marshal(joseHeader); err != nil { return nil, 0, nil, fmt.Errorf("unable to marshal jose header: %s", err) } if claimSetBytes, err = json.Marshal(claimSet); err != nil { return nil, 0, nil, fmt.Errorf("unable to marshal claim set: %s", err) } encodedJoseHeader := base64UrlEncode(joseHeaderBytes) encodedClaimSet := base64UrlEncode(claimSetBytes) payload := fmt.Sprintf("%s.%s", encodedJoseHeader, encodedClaimSet) var signatureBytes []byte if signatureBytes, _, err = signingKey.Sign(strings.NewReader(payload), crypto.SHA256); err != nil { return nil, 0, nil, fmt.Errorf("unable to sign jwt payload: %s", err) } signature := base64UrlEncode(signatureBytes) tokenString := fmt.Sprintf("%s.%s", payload, signature) t, err = token.NewToken(tokenString) return }
func serializePrivateKey(key libtrust.PrivateKey, ext string) (encoded []byte, err error) { if ext == ".json" || ext == ".jwk" { encoded, err = json.Marshal(key) if err != nil { return nil, fmt.Errorf("unable to encode private key JWK: %s", err) } } else { pemBlock, err := key.PEMBlock() if err != nil { return nil, fmt.Errorf("unable to encode private key PEM: %s", err) } encoded = pem.EncodeToMemory(pemBlock) } return }
// NewIdentityAuthTLSConfig creates a tls.Config for the client to use for // libtrust identity authentication func NewIdentityAuthTLSConfig(trustKey libtrust.PrivateKey, knownHostsPath, proto, addr string) (*tls.Config, error) { tlsConfig := createTLSConfig() // Load known hosts knownHosts, err := libtrust.LoadKeySetFile(knownHostsPath) if err != nil { return nil, fmt.Errorf("Could not load trusted hosts file: %s", err) } // Generate CA pool from known hosts allowedHosts, err := libtrust.FilterByHosts(knownHosts, addr, false) if err != nil { return nil, fmt.Errorf("Error filtering hosts: %s", err) } certPool, err := libtrust.GenerateCACertPool(trustKey, allowedHosts) if err != nil { return nil, fmt.Errorf("Could not create CA pool: %s", err) } tlsConfig.ServerName = "docker" tlsConfig.RootCAs = certPool // Generate client cert from trust key x509Cert, err := libtrust.GenerateSelfSignedClientCert(trustKey) if err != nil { return nil, fmt.Errorf("Certificate generation error: %s", err) } tlsConfig.Certificates = []tls.Certificate{{ Certificate: [][]byte{x509Cert.Raw}, PrivateKey: trustKey.CryptoPrivateKey(), Leaf: x509Cert, }} // Connect to server to see if it is a known host tlsConfig.InsecureSkipVerify = true testConn, err := tls.Dial(proto, addr, tlsConfig) if err != nil { return nil, fmt.Errorf("TLS Handshake error: %s", err) } opts := x509.VerifyOptions{ Roots: tlsConfig.RootCAs, CurrentTime: time.Now(), DNSName: tlsConfig.ServerName, Intermediates: x509.NewCertPool(), } certs := testConn.ConnectionState().PeerCertificates for i, cert := range certs { if i == 0 { continue } opts.Intermediates.AddCert(cert) } _, err = certs[0].Verify(opts) if err != nil { if _, ok := err.(x509.UnknownAuthorityError); ok { pubKey, err := libtrust.FromCryptoPublicKey(certs[0].PublicKey) if err != nil { return nil, fmt.Errorf("Error extracting public key from certificate: %s", err) } // If server is not a known host, prompt user to ask whether it should // be trusted and add to the known hosts file if promptUnknownKey(pubKey, addr) { pubKey.AddExtendedField("hosts", []string{addr}) err = libtrust.AddKeySetFile(knownHostsPath, pubKey) if err != nil { return nil, fmt.Errorf("Error saving updated host keys file: %s", err) } ca, err := libtrust.GenerateCACert(trustKey, pubKey) if err != nil { return nil, fmt.Errorf("Error generating CA: %s", err) } tlsConfig.RootCAs.AddCert(ca) } else { return nil, fmt.Errorf("Cancelling request due to invalid certificate") } } else { return nil, fmt.Errorf("TLS verification error: %s", err) } } testConn.Close() tlsConfig.InsecureSkipVerify = false return tlsConfig, nil }
func outputManifestFor(target string) { var pkey trust.PrivateKey if key != "" { var err error pkey, err = trust.LoadKeyFile(key) if err != nil { fmt.Printf("error loading key: %s\n", err.Error()) return } } if verbose { fmt.Errorf("signing with: %s\n", pkey.KeyID()) } f, err := os.Open(target) if err != nil { fmt.Printf("error opening file: %s\n", err.Error()) return } defer func() { if err := f.Close(); err != nil { panic(err) } }() var ( repo, tag string ) layers := LayerMap{} t := tar.NewReader(bufio.NewReader(f)) for { hdr, err := t.Next() if err == io.EOF { break } if strings.HasSuffix(hdr.Name, "layer.tar") { id := getLayerPrefix(hdr.Name) sum, _ := blobSumLayer(t) if _, ok := layers[id]; !ok { layers[id] = &Layer{Id: id} } else { layers[id].BlobSum = sum } } if strings.HasSuffix(hdr.Name, "json") { data, _ := ioutil.ReadAll(t) parent, id, _ := getLayerInfo(data) if _, ok := layers[id]; !ok { layers[id] = &Layer{Id: id, Parent: parent} } else { layers[id].Parent = parent } var img image.Image json.Unmarshal(data, &img) b, _ := json.Marshal(img) layers[id].Data = string(b) + "\n" } if hdr.Name == "repositories" { r, _ := ioutil.ReadAll(t) var raw map[string]interface{} if err := json.Unmarshal(r, &raw); err != nil { return } repo, tag = getRepoInfo(raw) if !strings.Contains(repo, "/") { repo = "library/" + repo } } } m := manifest.Manifest{ Versioned: versioned.Versioned{ SchemaVersion: 1, }, Name: repo, Tag: tag, Architecture: "amd64"} ll := getLayersFromMap(layers) for _, l := range getLayersInOrder(ll) { m.FSLayers = append(m.FSLayers, manifest.FSLayer{BlobSum: l.BlobSum}) m.History = append(m.History, manifest.History{V1Compatibility: l.Data}) } var x []byte if pkey != nil { var sm *manifest.SignedManifest sm, err = manifest.Sign(&m, pkey) x, err = sm.MarshalJSON() } else { x, err = json.MarshalIndent(m, "", " ") } if print_digest { dgstr, _ := digest.FromBytes(x) fmt.Println(string(dgstr)) } fmt.Println(string(x)) }