Skip to content

Commit ba21734

Browse files
committed
Add signature.GetUntrustedSignatureInformationWithoutVerifying
FIXME FIXME: TESTS Signed-off-by: Miloslav Trmač <[email protected]>
1 parent 1eb3b18 commit ba21734

2 files changed

Lines changed: 89 additions & 0 deletions

File tree

signature/mechanism.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,13 @@ package signature
44

55
import (
66
"bytes"
7+
"errors"
78
"fmt"
9+
"io/ioutil"
10+
"strings"
811

912
"github.com/mtrmac/gpgme"
13+
"golang.org/x/crypto/openpgp"
1014
)
1115

1216
// SigningMechanism abstracts a way to sign binary blobs and verify their signatures.
@@ -21,6 +25,12 @@ type SigningMechanism interface {
2125
Sign(input []byte, keyIdentity string) ([]byte, error)
2226
// Verify parses unverifiedSignature and returns the content and the signer's identity
2327
Verify(unverifiedSignature []byte) (contents []byte, keyIdentity string, err error)
28+
// UntrustedSignatureContents returns UNTRUSTED contents of the signature WITHOUT ANY VERIFICATION,
29+
// along with a short identifier of the key used for signing.
30+
// WARNING: The short key identifier (which correponds to "Key ID" for OpenPGP keys)
31+
// is NOT the same as a "key identity" used in other calls ot this interface, and
32+
// the values may have no recognizable relationship if the public key is not available.
33+
UntrustedSignatureContents(untrustedSignature []byte) (untrustedContents []byte, shortKeyIdentifier string, err error)
2434
}
2535

2636
// A GPG/OpenPGP signing mechanism.
@@ -119,3 +129,27 @@ func (m gpgSigningMechanism) Verify(unverifiedSignature []byte) (contents []byte
119129
}
120130
return signedBuffer.Bytes(), sig.Fingerprint, nil
121131
}
132+
133+
// UntrustedSignatureContents returns UNTRUSTED contents of the signature WITHOUT ANY VERIFICATION,
134+
// along with a short identifier of the key used for signing.
135+
// WARNING: The short key identifier (which correponds to "Key ID" for OpenPGP keys)
136+
// is NOT the same as a "key identity" used in other calls ot this interface, and
137+
// the values may have no recognizable relationship if the public key is not available.
138+
func (m gpgSigningMechanism) UntrustedSignatureContents(untrustedSignature []byte) (untrustedContents []byte, shortKeyIdentifier string, err error) {
139+
// This uses the Golang-native OpenPGP implementation instead of gpgme because we are not doing any cryptography.
140+
md, err := openpgp.ReadMessage(bytes.NewReader(untrustedSignature), openpgp.EntityList{}, nil, nil)
141+
if err != nil {
142+
return nil, "", err
143+
}
144+
if !md.IsSigned {
145+
return nil, "", errors.New("The input is not a signature")
146+
}
147+
content, err := ioutil.ReadAll(md.UnverifiedBody)
148+
if err != nil {
149+
return nil, "", err
150+
}
151+
152+
// Uppercase the key ID for minimal consistency with the gpgme-returned fingerprints
153+
// (but note that key ID is a suffix of the fingerprint only for V4 keys, not V3)!
154+
return content, strings.ToUpper(fmt.Sprintf("%016X", md.SignedByKeyId)), nil
155+
}

signature/signature.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,22 @@ type untrustedSignature struct {
4141
UntrustedTimestamp *int64
4242
}
4343

44+
// UntrustedSignatureInformation is information available in an untrusted signature.
45+
// This may be useful when debugging signature verification failures,
46+
// or when managing a set of signatures on a single image.
47+
//
48+
// WARNING: Do not use the contents of this for ANY security decisions,
49+
// and be VERY CAREFUL about showing this information to humans in any way which suggest that these values “are probably” reliable.
50+
// There is NO REASON to expect the values to be correct, or not intentionally misleading
51+
// (including things like “✅ Verified by $authority”)
52+
type UntrustedSignatureInformation struct {
53+
UntrustedDockerManifestDigest digest.Digest
54+
UntrustedDockerReference string // FIXME: more precise type?
55+
UntrustedCreatorID *string
56+
UntrustedTimestamp *time.Time
57+
UntrustedShortKeyIdentifier string
58+
}
59+
4460
// newUntrustedSignature returns an untrustedSignature object with
4561
// the specified primary contents and appropriate metadata.
4662
func newUntrustedSignature(dockerManifestDigest digest.Digest, dockerReference string) untrustedSignature {
@@ -229,3 +245,42 @@ func verifyAndExtractSignature(mech SigningMechanism, unverifiedSignature []byte
229245
DockerReference: unmatchedSignature.UntrustedDockerReference,
230246
}, nil
231247
}
248+
249+
// GetUntrustedSignatureInformationWithoutVerifying extracts information available in an untrusted signature,
250+
// WITHOUT doing any cryptographic verification.
251+
// This may be useful when debugging signature verification failures,
252+
// or when managing a set of signatures on a single image.
253+
//
254+
// WARNING: Do not use the contents of this for ANY security decisions,
255+
// and be VERY CAREFUL about showing this information to humans in any way which suggest that these values “are probably” reliable.
256+
// There is NO REASON to expect the values to be correct, or not intentionally misleading
257+
// (including things like “✅ Verified by $authority”)
258+
func GetUntrustedSignatureInformationWithoutVerifying(untrustedSignatureBytes []byte) (*UntrustedSignatureInformation, error) {
259+
// NOTE: This should eventualy do format autodetection.
260+
mech, err := NewGPGSigningMechanism()
261+
if err != nil {
262+
return nil, err
263+
}
264+
265+
untrustedContents, shortKeyIdentifier, err := mech.UntrustedSignatureContents(untrustedSignatureBytes)
266+
if err != nil {
267+
return nil, err
268+
}
269+
var untrustedDecodedContents untrustedSignature
270+
if err := json.Unmarshal(untrustedContents, &untrustedDecodedContents); err != nil {
271+
return nil, InvalidSignatureError{msg: err.Error()}
272+
}
273+
274+
var timestamp *time.Time // = nil
275+
if untrustedDecodedContents.UntrustedTimestamp != nil {
276+
ts := time.Unix(*untrustedDecodedContents.UntrustedTimestamp, 0)
277+
timestamp = &ts
278+
}
279+
return &UntrustedSignatureInformation{
280+
UntrustedDockerManifestDigest: untrustedDecodedContents.UntrustedDockerManifestDigest,
281+
UntrustedDockerReference: untrustedDecodedContents.UntrustedDockerReference,
282+
UntrustedCreatorID: untrustedDecodedContents.UntrustedCreatorID,
283+
UntrustedTimestamp: timestamp,
284+
UntrustedShortKeyIdentifier: shortKeyIdentifier,
285+
}, nil
286+
}

0 commit comments

Comments
 (0)