1 // Copyright 2013 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
15 "golang.org/x/crypto/openpgp/errors"
16 "golang.org/x/crypto/openpgp/s2k"
19 // SignatureV3 represents older version 3 signatures. These signatures are less secure
20 // than version 4 and should not be used to create new signatures. They are included
21 // here for backwards compatibility to read and validate with older key material.
22 // See RFC 4880, section 5.2.2.
23 type SignatureV3 struct {
25 CreationTime time.Time
27 PubKeyAlgo PublicKeyAlgorithm
31 RSASignature parsedMPI
32 DSASigR, DSASigS parsedMPI
35 func (sig *SignatureV3) parse(r io.Reader) (err error) {
36 // RFC 4880, section 5.2.2
38 if _, err = readFull(r, buf[:1]); err != nil {
41 if buf[0] < 2 || buf[0] > 3 {
42 err = errors.UnsupportedError("signature packet version " + strconv.Itoa(int(buf[0])))
45 if _, err = readFull(r, buf[:1]); err != nil {
49 err = errors.UnsupportedError(
50 "invalid hashed material length " + strconv.Itoa(int(buf[0])))
54 // Read hashed material: signature type + creation time
55 if _, err = readFull(r, buf[:5]); err != nil {
58 sig.SigType = SignatureType(buf[0])
59 t := binary.BigEndian.Uint32(buf[1:5])
60 sig.CreationTime = time.Unix(int64(t), 0)
62 // Eight-octet Key ID of signer.
63 if _, err = readFull(r, buf[:8]); err != nil {
66 sig.IssuerKeyId = binary.BigEndian.Uint64(buf[:])
68 // Public-key and hash algorithm
69 if _, err = readFull(r, buf[:2]); err != nil {
72 sig.PubKeyAlgo = PublicKeyAlgorithm(buf[0])
73 switch sig.PubKeyAlgo {
74 case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA:
76 err = errors.UnsupportedError("public key algorithm " + strconv.Itoa(int(sig.PubKeyAlgo)))
80 if sig.Hash, ok = s2k.HashIdToHash(buf[1]); !ok {
81 return errors.UnsupportedError("hash function " + strconv.Itoa(int(buf[2])))
84 // Two-octet field holding left 16 bits of signed hash value.
85 if _, err = readFull(r, sig.HashTag[:2]); err != nil {
89 switch sig.PubKeyAlgo {
90 case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
91 sig.RSASignature.bytes, sig.RSASignature.bitLength, err = readMPI(r)
93 if sig.DSASigR.bytes, sig.DSASigR.bitLength, err = readMPI(r); err != nil {
96 sig.DSASigS.bytes, sig.DSASigS.bitLength, err = readMPI(r)
103 // Serialize marshals sig to w. Sign, SignUserId or SignKey must have been
105 func (sig *SignatureV3) Serialize(w io.Writer) (err error) {
106 buf := make([]byte, 8)
108 // Write the sig type and creation time
109 buf[0] = byte(sig.SigType)
110 binary.BigEndian.PutUint32(buf[1:5], uint32(sig.CreationTime.Unix()))
111 if _, err = w.Write(buf[:5]); err != nil {
115 // Write the issuer long key ID
116 binary.BigEndian.PutUint64(buf[:8], sig.IssuerKeyId)
117 if _, err = w.Write(buf[:8]); err != nil {
121 // Write public key algorithm, hash ID, and hash value
122 buf[0] = byte(sig.PubKeyAlgo)
123 hashId, ok := s2k.HashToHashId(sig.Hash)
125 return errors.UnsupportedError(fmt.Sprintf("hash function %v", sig.Hash))
128 copy(buf[2:4], sig.HashTag[:])
129 if _, err = w.Write(buf[:4]); err != nil {
133 if sig.RSASignature.bytes == nil && sig.DSASigR.bytes == nil {
134 return errors.InvalidArgumentError("Signature: need to call Sign, SignUserId or SignKey before Serialize")
137 switch sig.PubKeyAlgo {
138 case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
139 err = writeMPIs(w, sig.RSASignature)
141 err = writeMPIs(w, sig.DSASigR, sig.DSASigS)