Source File
signature.go
Belonging Package
golang.org/x/crypto/openpgp/packet
package packet
import (
)
type Signature struct {
SigType SignatureType
PubKeyAlgo PublicKeyAlgorithm
Hash crypto.Hash
var [5]byte
_, = readFull(, [:1])
if != nil {
return
}
if [0] != 4 {
= errors.UnsupportedError("signature packet version " + strconv.Itoa(int([0])))
return
}
_, = readFull(, [:5])
if != nil {
return
}
.SigType = SignatureType([0])
.PubKeyAlgo = PublicKeyAlgorithm([1])
switch .PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA, PubKeyAlgoECDSA:
default:
= errors.UnsupportedError("public key algorithm " + strconv.Itoa(int(.PubKeyAlgo)))
return
}
var bool
.Hash, = s2k.HashIdToHash([2])
if ! {
return errors.UnsupportedError("hash function " + strconv.Itoa(int([2])))
}
:= int([3])<<8 | int([4])
:= 6 +
.HashSuffix = make([]byte, +6)
.HashSuffix[0] = 4
copy(.HashSuffix[1:], [:5])
:= .HashSuffix[6:]
_, = readFull(, )
if != nil {
return
:= .HashSuffix[:]
[0] = 4
[1] = 0xff
[2] = uint8( >> 24)
[3] = uint8( >> 16)
[4] = uint8( >> 8)
[5] = uint8()
= parseSignatureSubpackets(, , true)
if != nil {
return
}
_, = readFull(, [:2])
if != nil {
return
}
:= int([0])<<8 | int([1])
:= make([]byte, )
_, = readFull(, )
if != nil {
return
}
= parseSignatureSubpackets(, , false)
if != nil {
return
}
_, = readFull(, .HashTag[:2])
if != nil {
return
}
switch .PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
.RSASignature.bytes, .RSASignature.bitLength, = readMPI()
case PubKeyAlgoDSA:
.DSASigR.bytes, .DSASigR.bitLength, = readMPI()
if == nil {
.DSASigS.bytes, .DSASigS.bitLength, = readMPI()
}
case PubKeyAlgoECDSA:
.ECDSASigR.bytes, .ECDSASigR.bitLength, = readMPI()
if == nil {
.ECDSASigS.bytes, .ECDSASigS.bitLength, = readMPI()
}
default:
panic("unreachable")
}
return
}
func ( *Signature, []byte, bool) ( error) {
for len() > 0 {
, = parseSignatureSubpacket(, , )
if != nil {
return
}
}
if .CreationTime.IsZero() {
= errors.StructuralError("no creation time in signature")
}
return
}
type signatureSubpacketType uint8
const (
creationTimeSubpacket signatureSubpacketType = 2
signatureExpirationSubpacket signatureSubpacketType = 3
keyExpirationSubpacket signatureSubpacketType = 9
prefSymmetricAlgosSubpacket signatureSubpacketType = 11
issuerSubpacket signatureSubpacketType = 16
prefHashAlgosSubpacket signatureSubpacketType = 21
prefCompressionSubpacket signatureSubpacketType = 22
primaryUserIdSubpacket signatureSubpacketType = 25
keyFlagsSubpacket signatureSubpacketType = 27
reasonForRevocationSubpacket signatureSubpacketType = 29
featuresSubpacket signatureSubpacketType = 30
embeddedSignatureSubpacket signatureSubpacketType = 32
)
var (
uint32
signatureSubpacketType
bool
)
switch {
case [0] < 192:
= uint32([0])
= [1:]
case [0] < 255:
if len() < 2 {
goto
}
= uint32([0]-192)<<8 + uint32([1]) + 192
= [2:]
default:
if len() < 5 {
goto
}
= uint32([1])<<24 |
uint32([2])<<16 |
uint32([3])<<8 |
uint32([4])
= [5:]
}
if > uint32(len()) {
goto
}
= [:]
= [:]
if len() == 0 {
= errors.StructuralError("zero length signature subpacket")
return
}
= signatureSubpacketType([0] & 0x7f)
= [0]&0x80 == 0x80
= [1:]
.rawSubpackets = append(.rawSubpackets, outputSubpacket{, , , })
switch {
case creationTimeSubpacket:
if ! {
= errors.StructuralError("signature creation time in non-hashed area")
return
}
if len() != 4 {
= errors.StructuralError("signature creation time not four bytes")
return
}
:= binary.BigEndian.Uint32()
.CreationTime = time.Unix(int64(), 0)
if ! {
return
}
if len() != 4 {
= errors.StructuralError("expiration subpacket with bad length")
return
}
.SigLifetimeSecs = new(uint32)
*.SigLifetimeSecs = binary.BigEndian.Uint32()
if ! {
return
}
if len() != 4 {
= errors.StructuralError("key expiration subpacket with bad length")
return
}
.KeyLifetimeSecs = new(uint32)
*.KeyLifetimeSecs = binary.BigEndian.Uint32()
if ! {
return
}
.PreferredSymmetric = make([]byte, len())
copy(.PreferredSymmetric, )
if len() != 8 {
= errors.StructuralError("issuer subpacket with bad length")
return
}
.IssuerKeyId = new(uint64)
*.IssuerKeyId = binary.BigEndian.Uint64()
if ! {
return
}
.PreferredHash = make([]byte, len())
copy(.PreferredHash, )
if ! {
return
}
.PreferredCompression = make([]byte, len())
copy(.PreferredCompression, )
if ! {
return
}
if len() != 1 {
= errors.StructuralError("primary user id subpacket with bad length")
return
}
.IsPrimaryId = new(bool)
if [0] > 0 {
*.IsPrimaryId = true
}
if ! {
return
}
if len() == 0 {
= errors.StructuralError("empty key flags subpacket")
return
}
.FlagsValid = true
if [0]&KeyFlagCertify != 0 {
.FlagCertify = true
}
if [0]&KeyFlagSign != 0 {
.FlagSign = true
}
if [0]&KeyFlagEncryptCommunications != 0 {
.FlagEncryptCommunications = true
}
if [0]&KeyFlagEncryptStorage != 0 {
.FlagEncryptStorage = true
}
if ! {
return
}
if len() == 0 {
= errors.StructuralError("empty revocation reason subpacket")
return
}
.RevocationReason = new(uint8)
*.RevocationReason = [0]
.RevocationReasonText = string([1:])
if .EmbeddedSignature != nil {
= errors.StructuralError("Cannot have multiple embedded signatures")
return
}
if := .EmbeddedSignature.parse(bytes.NewBuffer()); != nil {
return nil,
}
if := .EmbeddedSignature.SigType; != SigTypePrimaryKeyBinding {
return nil, errors.StructuralError("cross-signature has unexpected type " + strconv.Itoa(int()))
}
default:
if {
= errors.UnsupportedError("unknown critical signature subpacket type " + strconv.Itoa(int()))
return
}
}
return
:
= errors.StructuralError("signature subpacket truncated")
return
}
func ( []outputSubpacket, bool) ( int) {
for , := range {
if .hashed == {
+= subpacketLengthLength(len(.contents) + 1)
+= 1 // type byte
+= len(.contents)
}
}
return
}
func ( []byte, []outputSubpacket, bool) {
for , := range {
if .hashed == {
:= serializeSubpacketLength(, len(.contents)+1)
[] = byte(.subpacketType)
= [1+:]
= copy(, .contents)
= [:]
}
}
return
}
func ( *Signature) ( time.Time) bool {
if .KeyLifetimeSecs == nil {
return false
}
:= .CreationTime.Add(time.Duration(*.KeyLifetimeSecs) * time.Second)
return .After()
}
func ( *Signature) () ( error) {
:= subpacketsLength(.outSubpackets, true)
var bool
:= 6 +
.HashSuffix = make([]byte, +6)
.HashSuffix[0] = 4
.HashSuffix[1] = uint8(.SigType)
.HashSuffix[2] = uint8(.PubKeyAlgo)
.HashSuffix[3], = s2k.HashToHashId(.Hash)
if ! {
.HashSuffix = nil
return errors.InvalidArgumentError("hash cannot be represented in OpenPGP: " + strconv.Itoa(int(.Hash)))
}
.HashSuffix[4] = byte( >> 8)
.HashSuffix[5] = byte()
serializeSubpackets(.HashSuffix[6:], .outSubpackets, true)
:= .HashSuffix[:]
[0] = 4
[1] = 0xff
[2] = byte( >> 24)
[3] = byte( >> 16)
[4] = byte( >> 8)
[5] = byte()
return
}
func ( *Signature) ( hash.Hash) ( []byte, error) {
= .buildHashSuffix()
if != nil {
return
}
.Write(.HashSuffix)
= .Sum(nil)
copy(.HashTag[:], )
return
}
func ( *Signature) ( hash.Hash, *PrivateKey, *Config) ( error) {
.outSubpackets = .buildSubpackets()
, := .signPrepareHash()
if != nil {
return
}
switch .PubKeyAlgo {
.RSASignature.bytes, = .PrivateKey.(crypto.Signer).Sign(.Random(), , .Hash)
.RSASignature.bitLength = uint16(8 * len(.RSASignature.bytes))
case PubKeyAlgoDSA:
:= .PrivateKey.(*dsa.PrivateKey)
, , = ecdsa.Sign(.Random(), , )
} else {
var []byte
, = .PrivateKey.(crypto.Signer).Sign(.Random(), , .Hash)
if == nil {
, , = unwrapECDSASig()
}
}
if == nil {
.ECDSASigR = fromBig()
.ECDSASigS = fromBig()
}
default:
= errors.UnsupportedError("public key algorithm: " + strconv.Itoa(int(.PubKeyAlgo)))
}
return
}
func ( *Signature) ( string, *PublicKey, *PrivateKey, *Config) error {
, := userIdSignatureHash(, , .Hash)
if != nil {
return
}
return .Sign(, , )
}
func ( *Signature) ( *PublicKey, *PrivateKey, *Config) error {
, := keySignatureHash(&.PublicKey, , .Hash)
if != nil {
return
}
return .Sign(, , )
}
func ( *Signature) ( io.Writer) ( error) {
if len(.outSubpackets) == 0 {
.outSubpackets = .rawSubpackets
}
if .RSASignature.bytes == nil && .DSASigR.bytes == nil && .ECDSASigR.bytes == nil {
return errors.InvalidArgumentError("Signature: need to call Sign, SignUserId or SignKey before Serialize")
}
:= 0
switch .PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
= 2 + len(.RSASignature.bytes)
case PubKeyAlgoDSA:
= 2 + len(.DSASigR.bytes)
+= 2 + len(.DSASigS.bytes)
case PubKeyAlgoECDSA:
= 2 + len(.ECDSASigR.bytes)
+= 2 + len(.ECDSASigS.bytes)
default:
panic("impossible")
}
:= subpacketsLength(.outSubpackets, false)
:= len(.HashSuffix) - 6 /* trailer not included */ +
2 /* length of unhashed subpackets */ + +
2 /* hash tag */ +
= serializeHeader(, packetTypeSignature, )
if != nil {
return
}
_, = .Write(.HashSuffix[:len(.HashSuffix)-6])
if != nil {
return
}
:= make([]byte, 2+)
[0] = byte( >> 8)
[1] = byte()
serializeSubpackets([2:], .outSubpackets, false)
_, = .Write()
if != nil {
return
}
_, = .Write(.HashTag[:])
if != nil {
return
}
switch .PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
= writeMPIs(, .RSASignature)
case PubKeyAlgoDSA:
= writeMPIs(, .DSASigR, .DSASigS)
case PubKeyAlgoECDSA:
= writeMPIs(, .ECDSASigR, .ECDSASigS)
default:
panic("impossible")
}
return
}
type outputSubpacket struct {
hashed bool // true if this subpacket is in the hashed area.
subpacketType signatureSubpacketType
isCritical bool
contents []byte
}
func ( *Signature) () ( []outputSubpacket) {
:= make([]byte, 4)
binary.BigEndian.PutUint32(, uint32(.CreationTime.Unix()))
= append(, outputSubpacket{true, creationTimeSubpacket, false, })
if .IssuerKeyId != nil {
:= make([]byte, 8)
binary.BigEndian.PutUint64(, *.IssuerKeyId)
= append(, outputSubpacket{true, issuerSubpacket, false, })
}
if .SigLifetimeSecs != nil && *.SigLifetimeSecs != 0 {
:= make([]byte, 4)
binary.BigEndian.PutUint32(, *.SigLifetimeSecs)
= append(, outputSubpacket{true, signatureExpirationSubpacket, true, })
}
if .FlagsValid {
var byte
if .FlagCertify {
|= KeyFlagCertify
}
if .FlagSign {
|= KeyFlagSign
}
if .FlagEncryptCommunications {
|= KeyFlagEncryptCommunications
}
if .FlagEncryptStorage {
|= KeyFlagEncryptStorage
}
= append(, outputSubpacket{true, keyFlagsSubpacket, false, []byte{}})
}
if .KeyLifetimeSecs != nil && *.KeyLifetimeSecs != 0 {
:= make([]byte, 4)
binary.BigEndian.PutUint32(, *.KeyLifetimeSecs)
= append(, outputSubpacket{true, keyExpirationSubpacket, true, })
}
if .IsPrimaryId != nil && *.IsPrimaryId {
= append(, outputSubpacket{true, primaryUserIdSubpacket, false, []byte{1}})
}
if len(.PreferredSymmetric) > 0 {
= append(, outputSubpacket{true, prefSymmetricAlgosSubpacket, false, .PreferredSymmetric})
}
if len(.PreferredHash) > 0 {
= append(, outputSubpacket{true, prefHashAlgosSubpacket, false, .PreferredHash})
}
if len(.PreferredCompression) > 0 {
= append(, outputSubpacket{true, prefCompressionSubpacket, false, .PreferredCompression})
}
return
![]() |
The pages are generated with Golds v0.3.2-preview. (GOOS=darwin GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |