func (g giImpl) PublicCertificates() ([]info.Certificate, error) { certs, err := appengine.PublicCertificates(g.aeCtx) if err != nil { return nil, err } ret := make([]info.Certificate, len(certs)) for i, c := range certs { ret[i] = info.Certificate(c) } return ret, nil }
// Certificate will return all public certificates assigned by App Engine in PEM format. func Certificate(ctx context.Context, w http.ResponseWriter, r *http.Request) (status int, err error) { var certs []appengine.Certificate if certs, err = appengine.PublicCertificates(ctx); err != nil { return http.StatusInternalServerError, err } w.Header().Add("Content-Type", "application/x-pem-file") for _, cert := range certs { w.Write([]byte("KeyName: \"" + cert.KeyName + "\"")) w.Write(cert.Data) } return http.StatusOK, nil }
// PublicCerts returns list of public certificates. func PublicCerts(c context.Context) (*PublicCertificates, error) { aeCerts, err := appengine.PublicCertificates(c) if err != nil { return nil, err } var certs []Certificate for _, ac := range aeCerts { certs = append(certs, Certificate{ KeyName: ac.KeyName, X509CertificatePEM: string(ac.Data), }) } return &PublicCertificates{ Certificates: certs, Timestamp: time.Now().Unix(), }, nil }
// Certificate will return all public certificates assigned by App Engine in PEM format. func Certificate(ctx context.Context, w http.ResponseWriter, r *http.Request) (int, error) { certs, err := appengine.PublicCertificates(ctx) if err != nil { return http.StatusInternalServerError, err } // TODO(flowlo): Is this really the appropriate MIME type? w.Header().Add("Content-Type", "application/x-pem-file") for _, cert := range certs { p := make([]byte, 13+len(cert.KeyName)+len(cert.Data)) p = append(p, []byte("KeyName: \""+cert.KeyName+"\"\n")...) p = append(p, cert.Data...) p = append(p, []byte("\n")...) if _, err := w.Write(p); err != nil { return http.StatusInternalServerError, err } } return http.StatusOK, nil }
// VerifyBytes verifies a signature produced by appengine.SignBytes. c must be a // context.Context created from appengine.NewContext. func VerifyBytes(c context.Context, bytes []byte, sig []byte) error { certs, err := appengine.PublicCertificates(c) if err != nil { return err } lastErr := ErrNoPublicCertificates signBytesHash := crypto.SHA256 h := signBytesHash.New() h.Write(bytes) hashed := h.Sum(nil) for _, cert := range certs { block, _ := pem.Decode(cert.Data) if block == nil { lastErr = ErrPemDecodeFailure continue } x509Cert, err := x509.ParseCertificate(block.Bytes) if err != nil { lastErr = err continue } pubkey, ok := x509Cert.PublicKey.(*rsa.PublicKey) if !ok { lastErr = ErrNotRSAPublicKey continue } err = rsa.VerifyPKCS1v15(pubkey, signBytesHash, hashed, sig) if err != nil { lastErr = err continue } return nil } return lastErr }
// Implements the Verify method from SigningMethod // For this signing method, a valid appengine.Context must be // passed as the key. func (s *SigningMethodAppEngine) Verify(signingString, signature string, key interface{}) error { var ctx context.Context switch k := key.(type) { case context.Context: ctx = k default: return jwt.ErrInvalidKey } var sig []byte var err error if sig, err = jwt.DecodeSegment(signature); err != nil { return err } var certs certificates certs, err = appengine.PublicCertificates(ctx) if err != nil { return err } hasher := sha256.New() hasher.Write([]byte(signingString)) var certErr error for _, cert := range certs { rsaKey, err := jwt.ParseRSAPublicKeyFromPEM(cert.Data) if err != nil { return err } if certErr = rsa.VerifyPKCS1v15(rsaKey, crypto.SHA256, hasher.Sum(nil), sig); certErr == nil { return nil } } return certErr }