mirror of
https://github.com/docker/docs.git
synced 2026-11-05 00:14:17 +03:00
GetCryptoService is a helper function and we have injected a specific http.ResponseWriter object for it to write back error message. Meanwhile the caller for that function checks whether the cryptoService is nil or not and return immediately if it is nil. I think it's not a good idea to write back HTTP response in the helper function, it's the caller's work and thus there is no need to inject the specific ResponseWriter object into it. Signed-off-by: Hu Keping <hukeping@huawei.com>
206 lines
6.1 KiB
Go
206 lines
6.1 KiB
Go
package api
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"github.com/docker/notary/signer"
|
|
"github.com/docker/notary/signer/keys"
|
|
"github.com/docker/notary/tuf/signed"
|
|
"github.com/gorilla/mux"
|
|
|
|
pb "github.com/docker/notary/proto"
|
|
)
|
|
|
|
// Handlers sets up all the handers for the routes, injecting a specific CryptoService object for them to use
|
|
func Handlers(cryptoServices signer.CryptoServiceIndex) *mux.Router {
|
|
r := mux.NewRouter()
|
|
|
|
r.Methods("GET").Path("/{ID}").Handler(KeyInfo(cryptoServices))
|
|
r.Methods("POST").Path("/new/{Algorithm}").Handler(CreateKey(cryptoServices))
|
|
r.Methods("POST").Path("/delete").Handler(DeleteKey(cryptoServices))
|
|
r.Methods("POST").Path("/sign").Handler(Sign(cryptoServices))
|
|
return r
|
|
}
|
|
|
|
// getCryptoService handles looking up the correct signing service, given the
|
|
// algorithm specified in the HTTP request. If the algorithm isn't specified
|
|
// or isn't supported, an error is returned to the client and this function
|
|
// returns a nil CryptoService
|
|
func getCryptoService(algorithm string, cryptoServices signer.CryptoServiceIndex) (signed.CryptoService, error) {
|
|
if algorithm == "" {
|
|
return nil, fmt.Errorf("algorithm not specified")
|
|
}
|
|
|
|
if service, ok := cryptoServices[algorithm]; ok {
|
|
return service, nil
|
|
}
|
|
|
|
return nil, fmt.Errorf("algorithm " + algorithm + " not supported")
|
|
}
|
|
|
|
// KeyInfo returns a Handler that given a specific Key ID param, returns the public key bits of that key
|
|
func KeyInfo(cryptoServices signer.CryptoServiceIndex) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
vars := mux.Vars(r)
|
|
|
|
tufKey, _, err := FindKeyByID(cryptoServices, &pb.KeyID{ID: vars["ID"]})
|
|
if err != nil {
|
|
switch err {
|
|
// If we received an ErrInvalidKeyID, the key doesn't exist, return 404
|
|
case keys.ErrInvalidKeyID:
|
|
w.WriteHeader(http.StatusNotFound)
|
|
w.Write([]byte(err.Error()))
|
|
return
|
|
// If we received anything else, it is unexpected, and we return a 500
|
|
default:
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
w.Write([]byte(err.Error()))
|
|
return
|
|
}
|
|
}
|
|
key := &pb.PublicKey{
|
|
KeyInfo: &pb.KeyInfo{
|
|
KeyID: &pb.KeyID{ID: tufKey.ID()},
|
|
Algorithm: &pb.Algorithm{Algorithm: tufKey.Algorithm()},
|
|
},
|
|
PublicKey: tufKey.Public(),
|
|
}
|
|
json.NewEncoder(w).Encode(key)
|
|
return
|
|
})
|
|
}
|
|
|
|
// CreateKey returns a handler that generates a new key using the provided
|
|
// algorithm. Only the public component of the key is returned.
|
|
func CreateKey(cryptoServices signer.CryptoServiceIndex) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
vars := mux.Vars(r)
|
|
cryptoService, err := getCryptoService(vars["Algorithm"], cryptoServices)
|
|
if err != nil {
|
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
tufKey, err := cryptoService.Create("", vars["Algorithm"])
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
w.Write([]byte(err.Error()))
|
|
return
|
|
}
|
|
key := &pb.PublicKey{
|
|
KeyInfo: &pb.KeyInfo{
|
|
KeyID: &pb.KeyID{ID: tufKey.ID()},
|
|
Algorithm: &pb.Algorithm{Algorithm: tufKey.Algorithm()},
|
|
},
|
|
PublicKey: tufKey.Public(),
|
|
}
|
|
json.NewEncoder(w).Encode(key)
|
|
return
|
|
})
|
|
}
|
|
|
|
// DeleteKey returns a handler that delete a specific KeyID
|
|
func DeleteKey(cryptoServices signer.CryptoServiceIndex) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
var keyID *pb.KeyID
|
|
err := json.NewDecoder(r.Body).Decode(&keyID)
|
|
defer r.Body.Close()
|
|
if err != nil || keyID.ID == "" {
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
jsonErr, _ := json.Marshal("Malformed request")
|
|
w.Write([]byte(jsonErr))
|
|
return
|
|
}
|
|
|
|
_, cryptoService, err := FindKeyByID(cryptoServices, keyID)
|
|
|
|
if err != nil {
|
|
switch err {
|
|
// If we received an ErrInvalidKeyID, the key doesn't exist, return 404
|
|
case keys.ErrInvalidKeyID:
|
|
w.WriteHeader(http.StatusNotFound)
|
|
w.Write([]byte(err.Error()))
|
|
return
|
|
// If we received anything else, it is unexpected, and we return a 500
|
|
default:
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
w.Write([]byte(err.Error()))
|
|
return
|
|
}
|
|
}
|
|
|
|
if err = cryptoService.RemoveKey(keyID.ID); err != nil {
|
|
switch err {
|
|
// If we received an ErrInvalidKeyID, the key doesn't exist, return 404
|
|
case keys.ErrInvalidKeyID:
|
|
w.WriteHeader(http.StatusNotFound)
|
|
w.Write([]byte(err.Error()))
|
|
return
|
|
// If we received anything else, it is unexpected, and we return a 500
|
|
default:
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
w.Write([]byte(err.Error()))
|
|
return
|
|
}
|
|
}
|
|
// In case we successfully delete this key, return 200
|
|
return
|
|
})
|
|
}
|
|
|
|
// Sign returns a handler that is able to perform signatures on a given blob
|
|
func Sign(cryptoServices signer.CryptoServiceIndex) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
var sigRequest *pb.SignatureRequest
|
|
err := json.NewDecoder(r.Body).Decode(&sigRequest)
|
|
defer r.Body.Close()
|
|
if err != nil || sigRequest.Content == nil ||
|
|
sigRequest.KeyID == nil {
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
jsonErr, _ := json.Marshal("Malformed request")
|
|
w.Write([]byte(jsonErr))
|
|
return
|
|
}
|
|
|
|
tufKey, cryptoService, err := FindKeyByID(cryptoServices, sigRequest.KeyID)
|
|
if err == keys.ErrInvalidKeyID {
|
|
w.WriteHeader(http.StatusNotFound)
|
|
w.Write([]byte(err.Error()))
|
|
return
|
|
} else if err != nil {
|
|
// We got an unexpected error
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
w.Write([]byte(err.Error()))
|
|
return
|
|
}
|
|
|
|
privKey, _, err := cryptoService.GetPrivateKey(tufKey.ID())
|
|
if err != nil {
|
|
// We got an unexpected error
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
w.Write([]byte(err.Error()))
|
|
return
|
|
}
|
|
sig, err := privKey.Sign(rand.Reader, sigRequest.Content, nil)
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
w.Write([]byte(err.Error()))
|
|
return
|
|
}
|
|
signature := &pb.Signature{
|
|
KeyInfo: &pb.KeyInfo{
|
|
KeyID: &pb.KeyID{ID: tufKey.ID()},
|
|
Algorithm: &pb.Algorithm{Algorithm: tufKey.Algorithm()},
|
|
},
|
|
Algorithm: &pb.Algorithm{Algorithm: privKey.SignatureAlgorithm().String()},
|
|
Content: sig,
|
|
}
|
|
|
|
json.NewEncoder(w).Encode(signature)
|
|
return
|
|
})
|
|
}
|