mirror of
https://github.com/containers/skopeo.git
synced 2025-09-23 02:48:26 +00:00
Vendor after merging mtrmac/image:unverified-contents
This commit is contained in:
7
vendor/github.com/containers/image/signature/docker.go
generated
vendored
7
vendor/github.com/containers/image/signature/docker.go
generated
vendored
@@ -16,12 +16,7 @@ func SignDockerManifest(m []byte, dockerReference string, mech SigningMechanism,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sig := privateSignature{
|
||||
Signature{
|
||||
DockerManifestDigest: manifestDigest,
|
||||
DockerReference: dockerReference,
|
||||
},
|
||||
}
|
||||
sig := newUntrustedSignature(manifestDigest, dockerReference)
|
||||
return sig.sign(mech, keyIdentity)
|
||||
}
|
||||
|
||||
|
19
vendor/github.com/containers/image/signature/json.go
generated
vendored
19
vendor/github.com/containers/image/signature/json.go
generated
vendored
@@ -29,6 +29,23 @@ func validateExactMapKeys(m map[string]interface{}, expectedKeys ...string) erro
|
||||
return nil
|
||||
}
|
||||
|
||||
// int64Field returns a member fieldName of m, if it is an int64, or an error.
|
||||
func int64Field(m map[string]interface{}, fieldName string) (int64, error) {
|
||||
untyped, ok := m[fieldName]
|
||||
if !ok {
|
||||
return -1, jsonFormatError(fmt.Sprintf("Field %s missing", fieldName))
|
||||
}
|
||||
f, ok := untyped.(float64)
|
||||
if !ok {
|
||||
return -1, jsonFormatError(fmt.Sprintf("Field %s is not a number", fieldName))
|
||||
}
|
||||
v := int64(f)
|
||||
if float64(v) != f {
|
||||
return -1, jsonFormatError(fmt.Sprintf("Field %s is not an integer", fieldName))
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// mapField returns a member fieldName of m, if it is a JSON map, or an error.
|
||||
func mapField(m map[string]interface{}, fieldName string) (map[string]interface{}, error) {
|
||||
untyped, ok := m[fieldName]
|
||||
@@ -50,7 +67,7 @@ func stringField(m map[string]interface{}, fieldName string) (string, error) {
|
||||
}
|
||||
v, ok := untyped.(string)
|
||||
if !ok {
|
||||
return "", jsonFormatError(fmt.Sprintf("Field %s is not a JSON object", fieldName))
|
||||
return "", jsonFormatError(fmt.Sprintf("Field %s is not a string", fieldName))
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
38
vendor/github.com/containers/image/signature/mechanism.go
generated
vendored
38
vendor/github.com/containers/image/signature/mechanism.go
generated
vendored
@@ -4,9 +4,13 @@ package signature
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
|
||||
"github.com/mtrmac/gpgme"
|
||||
"golang.org/x/crypto/openpgp"
|
||||
)
|
||||
|
||||
// SigningMechanism abstracts a way to sign binary blobs and verify their signatures.
|
||||
@@ -21,6 +25,12 @@ type SigningMechanism interface {
|
||||
Sign(input []byte, keyIdentity string) ([]byte, error)
|
||||
// Verify parses unverifiedSignature and returns the content and the signer's identity
|
||||
Verify(unverifiedSignature []byte) (contents []byte, keyIdentity string, err error)
|
||||
// UntrustedSignatureContents returns UNTRUSTED contents of the signature WITHOUT ANY VERIFICATION,
|
||||
// along with a short identifier of the key used for signing.
|
||||
// WARNING: The short key identifier (which correponds to "Key ID" for OpenPGP keys)
|
||||
// is NOT the same as a "key identity" used in other calls ot this interface, and
|
||||
// the values may have no recognizable relationship if the public key is not available.
|
||||
UntrustedSignatureContents(untrustedSignature []byte) (untrustedContents []byte, shortKeyIdentifier string, err error)
|
||||
}
|
||||
|
||||
// A GPG/OpenPGP signing mechanism.
|
||||
@@ -119,3 +129,31 @@ func (m gpgSigningMechanism) Verify(unverifiedSignature []byte) (contents []byte
|
||||
}
|
||||
return signedBuffer.Bytes(), sig.Fingerprint, nil
|
||||
}
|
||||
|
||||
// UntrustedSignatureContents returns UNTRUSTED contents of the signature WITHOUT ANY VERIFICATION,
|
||||
// along with a short identifier of the key used for signing.
|
||||
// WARNING: The short key identifier (which correponds to "Key ID" for OpenPGP keys)
|
||||
// is NOT the same as a "key identity" used in other calls ot this interface, and
|
||||
// the values may have no recognizable relationship if the public key is not available.
|
||||
func (m gpgSigningMechanism) UntrustedSignatureContents(untrustedSignature []byte) (untrustedContents []byte, shortKeyIdentifier string, err error) {
|
||||
// This uses the Golang-native OpenPGP implementation instead of gpgme because we are not doing any cryptography.
|
||||
md, err := openpgp.ReadMessage(bytes.NewReader(untrustedSignature), openpgp.EntityList{}, nil, nil)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
if !md.IsSigned {
|
||||
return nil, "", errors.New("The input is not a signature")
|
||||
}
|
||||
content, err := ioutil.ReadAll(md.UnverifiedBody)
|
||||
if err != nil {
|
||||
// Coverage: An error during reading the body can happen only if
|
||||
// 1) the message is encrypted, which is not our case (and we don’t give ReadMessage the key
|
||||
// to decrypt the contents anyway), or
|
||||
// 2) the message is signed AND we give ReadMessage a correspnding public key, which we don’t.
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
// Uppercase the key ID for minimal consistency with the gpgme-returned fingerprints
|
||||
// (but note that key ID is a suffix of the fingerprint only for V4 keys, not V3)!
|
||||
return content, strings.ToUpper(fmt.Sprintf("%016X", md.SignedByKeyId)), nil
|
||||
}
|
||||
|
159
vendor/github.com/containers/image/signature/signature.go
generated
vendored
159
vendor/github.com/containers/image/signature/signature.go
generated
vendored
@@ -27,37 +27,74 @@ func (err InvalidSignatureError) Error() string {
|
||||
}
|
||||
|
||||
// Signature is a parsed content of a signature.
|
||||
// The only way to get this structure from a blob should be as a return value from a successful call to verifyAndExtractSignature below.
|
||||
type Signature struct {
|
||||
DockerManifestDigest digest.Digest
|
||||
DockerReference string // FIXME: more precise type?
|
||||
}
|
||||
|
||||
// Wrap signature to add to it some methods which we don't want to make public.
|
||||
type privateSignature struct {
|
||||
Signature
|
||||
// untrustedSignature is a parsed content of a signature.
|
||||
type untrustedSignature struct {
|
||||
UntrustedDockerManifestDigest digest.Digest
|
||||
UntrustedDockerReference string // FIXME: more precise type?
|
||||
UntrustedCreatorID *string
|
||||
// This is intentionally an int64; the native JSON float64 type would allow to represent _some_ sub-second precision,
|
||||
// but not nearly enough (with current timestamp values, a single unit in the last place is on the order of hundreds of nanoseconds).
|
||||
// So, this is explicitly an int64, and we reject fractional values. If we did need more precise timestamps eventually,
|
||||
// we would add another field, UntrustedTimestampNS int64.
|
||||
UntrustedTimestamp *int64
|
||||
}
|
||||
|
||||
// Compile-time check that privateSignature implements json.Marshaler
|
||||
var _ json.Marshaler = (*privateSignature)(nil)
|
||||
// UntrustedSignatureInformation is information available in an untrusted signature.
|
||||
// This may be useful when debugging signature verification failures,
|
||||
// or when managing a set of signatures on a single image.
|
||||
//
|
||||
// WARNING: Do not use the contents of this for ANY security decisions,
|
||||
// and be VERY CAREFUL about showing this information to humans in any way which suggest that these values “are probably” reliable.
|
||||
// There is NO REASON to expect the values to be correct, or not intentionally misleading
|
||||
// (including things like “✅ Verified by $authority”)
|
||||
type UntrustedSignatureInformation struct {
|
||||
UntrustedDockerManifestDigest digest.Digest
|
||||
UntrustedDockerReference string // FIXME: more precise type?
|
||||
UntrustedCreatorID *string
|
||||
UntrustedTimestamp *time.Time
|
||||
UntrustedShortKeyIdentifier string
|
||||
}
|
||||
|
||||
// newUntrustedSignature returns an untrustedSignature object with
|
||||
// the specified primary contents and appropriate metadata.
|
||||
func newUntrustedSignature(dockerManifestDigest digest.Digest, dockerReference string) untrustedSignature {
|
||||
// Use intermediate variables for these values so that we can take their addresses.
|
||||
// Golang guarantees that they will have a new address on every execution.
|
||||
creatorID := "atomic " + version.Version
|
||||
timestamp := time.Now().Unix()
|
||||
return untrustedSignature{
|
||||
UntrustedDockerManifestDigest: dockerManifestDigest,
|
||||
UntrustedDockerReference: dockerReference,
|
||||
UntrustedCreatorID: &creatorID,
|
||||
UntrustedTimestamp: ×tamp,
|
||||
}
|
||||
}
|
||||
|
||||
// Compile-time check that untrustedSignature implements json.Marshaler
|
||||
var _ json.Marshaler = (*untrustedSignature)(nil)
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface.
|
||||
func (s privateSignature) MarshalJSON() ([]byte, error) {
|
||||
return s.marshalJSONWithVariables(time.Now().UTC().Unix(), "atomic "+version.Version)
|
||||
}
|
||||
|
||||
// Implementation of MarshalJSON, with a caller-chosen values of the variable items to help testing.
|
||||
func (s privateSignature) marshalJSONWithVariables(timestamp int64, creatorID string) ([]byte, error) {
|
||||
if s.DockerManifestDigest == "" || s.DockerReference == "" {
|
||||
func (s untrustedSignature) MarshalJSON() ([]byte, error) {
|
||||
if s.UntrustedDockerManifestDigest == "" || s.UntrustedDockerReference == "" {
|
||||
return nil, errors.New("Unexpected empty signature content")
|
||||
}
|
||||
critical := map[string]interface{}{
|
||||
"type": signatureType,
|
||||
"image": map[string]string{"docker-manifest-digest": s.DockerManifestDigest.String()},
|
||||
"identity": map[string]string{"docker-reference": s.DockerReference},
|
||||
"image": map[string]string{"docker-manifest-digest": s.UntrustedDockerManifestDigest.String()},
|
||||
"identity": map[string]string{"docker-reference": s.UntrustedDockerReference},
|
||||
}
|
||||
optional := map[string]interface{}{
|
||||
"creator": creatorID,
|
||||
"timestamp": timestamp,
|
||||
optional := map[string]interface{}{}
|
||||
if s.UntrustedCreatorID != nil {
|
||||
optional["creator"] = *s.UntrustedCreatorID
|
||||
}
|
||||
if s.UntrustedTimestamp != nil {
|
||||
optional["timestamp"] = *s.UntrustedTimestamp
|
||||
}
|
||||
signature := map[string]interface{}{
|
||||
"critical": critical,
|
||||
@@ -66,11 +103,11 @@ func (s privateSignature) marshalJSONWithVariables(timestamp int64, creatorID st
|
||||
return json.Marshal(signature)
|
||||
}
|
||||
|
||||
// Compile-time check that privateSignature implements json.Unmarshaler
|
||||
var _ json.Unmarshaler = (*privateSignature)(nil)
|
||||
// Compile-time check that untrustedSignature implements json.Unmarshaler
|
||||
var _ json.Unmarshaler = (*untrustedSignature)(nil)
|
||||
|
||||
// UnmarshalJSON implements the json.Unmarshaler interface
|
||||
func (s *privateSignature) UnmarshalJSON(data []byte) error {
|
||||
func (s *untrustedSignature) UnmarshalJSON(data []byte) error {
|
||||
err := s.strictUnmarshalJSON(data)
|
||||
if err != nil {
|
||||
if _, ok := err.(jsonFormatError); ok {
|
||||
@@ -82,7 +119,7 @@ func (s *privateSignature) UnmarshalJSON(data []byte) error {
|
||||
|
||||
// strictUnmarshalJSON is UnmarshalJSON, except that it may return the internal jsonFormatError error type.
|
||||
// Splitting it into a separate function allows us to do the jsonFormatError → InvalidSignatureError in a single place, the caller.
|
||||
func (s *privateSignature) strictUnmarshalJSON(data []byte) error {
|
||||
func (s *untrustedSignature) strictUnmarshalJSON(data []byte) error {
|
||||
var untyped interface{}
|
||||
if err := json.Unmarshal(data, &untyped); err != nil {
|
||||
return err
|
||||
@@ -107,7 +144,20 @@ func (s *privateSignature) strictUnmarshalJSON(data []byte) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_ = optional // We don't use anything from here for now.
|
||||
if _, ok := optional["creator"]; ok {
|
||||
creatorID, err := stringField(optional, "creator")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.UntrustedCreatorID = &creatorID
|
||||
}
|
||||
if _, ok := optional["timestamp"]; ok {
|
||||
timestamp, err := int64Field(optional, "timestamp")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.UntrustedTimestamp = ×tamp
|
||||
}
|
||||
|
||||
t, err := stringField(c, "type")
|
||||
if err != nil {
|
||||
@@ -128,7 +178,7 @@ func (s *privateSignature) strictUnmarshalJSON(data []byte) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.DockerManifestDigest = digest.Digest(digestString)
|
||||
s.UntrustedDockerManifestDigest = digest.Digest(digestString)
|
||||
|
||||
identity, err := mapField(c, "identity")
|
||||
if err != nil {
|
||||
@@ -141,13 +191,18 @@ func (s *privateSignature) strictUnmarshalJSON(data []byte) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.DockerReference = reference
|
||||
s.UntrustedDockerReference = reference
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Sign formats the signature and returns a blob signed using mech and keyIdentity
|
||||
func (s privateSignature) sign(mech SigningMechanism, keyIdentity string) ([]byte, error) {
|
||||
// (If it seems surprising that this is a method on untrustedSignature, note that there
|
||||
// isn’t a good reason to think that a key used by the user is trusted by any component
|
||||
// of the system just because it is a private key — actually the presence of a private key
|
||||
// on the system increases the likelihood of an a successful attack on that private key
|
||||
// on that particular system.)
|
||||
func (s untrustedSignature) sign(mech SigningMechanism, keyIdentity string) ([]byte, error) {
|
||||
json, err := json.Marshal(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -159,7 +214,7 @@ func (s privateSignature) sign(mech SigningMechanism, keyIdentity string) ([]byt
|
||||
// signatureAcceptanceRules specifies how to decide whether an untrusted signature is acceptable.
|
||||
// We centralize the actual parsing and data extraction in verifyAndExtractSignature; this supplies
|
||||
// the policy. We use an object instead of supplying func parameters to verifyAndExtractSignature
|
||||
// because all of the functions have the same type, so there is a risk of exchanging the functions;
|
||||
// because the functions have the same or similar types, so there is a risk of exchanging the functions;
|
||||
// named members of this struct are more explicit.
|
||||
type signatureAcceptanceRules struct {
|
||||
validateKeyIdentity func(string) error
|
||||
@@ -178,16 +233,58 @@ func verifyAndExtractSignature(mech SigningMechanism, unverifiedSignature []byte
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var unmatchedSignature privateSignature
|
||||
var unmatchedSignature untrustedSignature
|
||||
if err := json.Unmarshal(signed, &unmatchedSignature); err != nil {
|
||||
return nil, InvalidSignatureError{msg: err.Error()}
|
||||
}
|
||||
if err := rules.validateSignedDockerManifestDigest(unmatchedSignature.DockerManifestDigest); err != nil {
|
||||
if err := rules.validateSignedDockerManifestDigest(unmatchedSignature.UntrustedDockerManifestDigest); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rules.validateSignedDockerReference(unmatchedSignature.DockerReference); err != nil {
|
||||
if err := rules.validateSignedDockerReference(unmatchedSignature.UntrustedDockerReference); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
signature := unmatchedSignature.Signature // Policy OK.
|
||||
return &signature, nil
|
||||
// signatureAcceptanceRules have accepted this value.
|
||||
return &Signature{
|
||||
DockerManifestDigest: unmatchedSignature.UntrustedDockerManifestDigest,
|
||||
DockerReference: unmatchedSignature.UntrustedDockerReference,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetUntrustedSignatureInformationWithoutVerifying extracts information available in an untrusted signature,
|
||||
// WITHOUT doing any cryptographic verification.
|
||||
// This may be useful when debugging signature verification failures,
|
||||
// or when managing a set of signatures on a single image.
|
||||
//
|
||||
// WARNING: Do not use the contents of this for ANY security decisions,
|
||||
// and be VERY CAREFUL about showing this information to humans in any way which suggest that these values “are probably” reliable.
|
||||
// There is NO REASON to expect the values to be correct, or not intentionally misleading
|
||||
// (including things like “✅ Verified by $authority”)
|
||||
func GetUntrustedSignatureInformationWithoutVerifying(untrustedSignatureBytes []byte) (*UntrustedSignatureInformation, error) {
|
||||
// NOTE: This should eventualy do format autodetection.
|
||||
mech, err := NewGPGSigningMechanism()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
untrustedContents, shortKeyIdentifier, err := mech.UntrustedSignatureContents(untrustedSignatureBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var untrustedDecodedContents untrustedSignature
|
||||
if err := json.Unmarshal(untrustedContents, &untrustedDecodedContents); err != nil {
|
||||
return nil, InvalidSignatureError{msg: err.Error()}
|
||||
}
|
||||
|
||||
var timestamp *time.Time // = nil
|
||||
if untrustedDecodedContents.UntrustedTimestamp != nil {
|
||||
ts := time.Unix(*untrustedDecodedContents.UntrustedTimestamp, 0)
|
||||
timestamp = &ts
|
||||
}
|
||||
return &UntrustedSignatureInformation{
|
||||
UntrustedDockerManifestDigest: untrustedDecodedContents.UntrustedDockerManifestDigest,
|
||||
UntrustedDockerReference: untrustedDecodedContents.UntrustedDockerReference,
|
||||
UntrustedCreatorID: untrustedDecodedContents.UntrustedCreatorID,
|
||||
UntrustedTimestamp: timestamp,
|
||||
UntrustedShortKeyIdentifier: shortKeyIdentifier,
|
||||
}, nil
|
||||
}
|
||||
|
2
vendor/github.com/docker/distribution/reference/reference.go
generated
vendored
2
vendor/github.com/docker/distribution/reference/reference.go
generated
vendored
@@ -399,7 +399,7 @@ func (r repository) Path() string {
|
||||
type digestReference digest.Digest
|
||||
|
||||
func (d digestReference) String() string {
|
||||
return d.String()
|
||||
return digest.Digest(d).String()
|
||||
}
|
||||
|
||||
func (d digestReference) Digest() digest.Digest {
|
||||
|
Reference in New Issue
Block a user