]>
Commit | Line | Data |
---|---|---|
c680a8e1 RS |
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. | |
4 | ||
5 | package packet | |
6 | ||
7 | import ( | |
8 | "crypto" | |
9 | "encoding/binary" | |
10 | "fmt" | |
11 | "io" | |
12 | "strconv" | |
13 | "time" | |
14 | ||
15 | "golang.org/x/crypto/openpgp/errors" | |
16 | "golang.org/x/crypto/openpgp/s2k" | |
17 | ) | |
18 | ||
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 { | |
24 | SigType SignatureType | |
25 | CreationTime time.Time | |
26 | IssuerKeyId uint64 | |
27 | PubKeyAlgo PublicKeyAlgorithm | |
28 | Hash crypto.Hash | |
29 | HashTag [2]byte | |
30 | ||
31 | RSASignature parsedMPI | |
32 | DSASigR, DSASigS parsedMPI | |
33 | } | |
34 | ||
35 | func (sig *SignatureV3) parse(r io.Reader) (err error) { | |
36 | // RFC 4880, section 5.2.2 | |
37 | var buf [8]byte | |
38 | if _, err = readFull(r, buf[:1]); err != nil { | |
39 | return | |
40 | } | |
41 | if buf[0] < 2 || buf[0] > 3 { | |
42 | err = errors.UnsupportedError("signature packet version " + strconv.Itoa(int(buf[0]))) | |
43 | return | |
44 | } | |
45 | if _, err = readFull(r, buf[:1]); err != nil { | |
46 | return | |
47 | } | |
48 | if buf[0] != 5 { | |
49 | err = errors.UnsupportedError( | |
50 | "invalid hashed material length " + strconv.Itoa(int(buf[0]))) | |
51 | return | |
52 | } | |
53 | ||
54 | // Read hashed material: signature type + creation time | |
55 | if _, err = readFull(r, buf[:5]); err != nil { | |
56 | return | |
57 | } | |
58 | sig.SigType = SignatureType(buf[0]) | |
59 | t := binary.BigEndian.Uint32(buf[1:5]) | |
60 | sig.CreationTime = time.Unix(int64(t), 0) | |
61 | ||
62 | // Eight-octet Key ID of signer. | |
63 | if _, err = readFull(r, buf[:8]); err != nil { | |
64 | return | |
65 | } | |
66 | sig.IssuerKeyId = binary.BigEndian.Uint64(buf[:]) | |
67 | ||
68 | // Public-key and hash algorithm | |
69 | if _, err = readFull(r, buf[:2]); err != nil { | |
70 | return | |
71 | } | |
72 | sig.PubKeyAlgo = PublicKeyAlgorithm(buf[0]) | |
73 | switch sig.PubKeyAlgo { | |
74 | case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA: | |
75 | default: | |
76 | err = errors.UnsupportedError("public key algorithm " + strconv.Itoa(int(sig.PubKeyAlgo))) | |
77 | return | |
78 | } | |
79 | var ok bool | |
80 | if sig.Hash, ok = s2k.HashIdToHash(buf[1]); !ok { | |
81 | return errors.UnsupportedError("hash function " + strconv.Itoa(int(buf[2]))) | |
82 | } | |
83 | ||
84 | // Two-octet field holding left 16 bits of signed hash value. | |
85 | if _, err = readFull(r, sig.HashTag[:2]); err != nil { | |
86 | return | |
87 | } | |
88 | ||
89 | switch sig.PubKeyAlgo { | |
90 | case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: | |
91 | sig.RSASignature.bytes, sig.RSASignature.bitLength, err = readMPI(r) | |
92 | case PubKeyAlgoDSA: | |
93 | if sig.DSASigR.bytes, sig.DSASigR.bitLength, err = readMPI(r); err != nil { | |
94 | return | |
95 | } | |
96 | sig.DSASigS.bytes, sig.DSASigS.bitLength, err = readMPI(r) | |
97 | default: | |
98 | panic("unreachable") | |
99 | } | |
100 | return | |
101 | } | |
102 | ||
103 | // Serialize marshals sig to w. Sign, SignUserId or SignKey must have been | |
104 | // called first. | |
105 | func (sig *SignatureV3) Serialize(w io.Writer) (err error) { | |
106 | buf := make([]byte, 8) | |
107 | ||
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 { | |
112 | return | |
113 | } | |
114 | ||
115 | // Write the issuer long key ID | |
116 | binary.BigEndian.PutUint64(buf[:8], sig.IssuerKeyId) | |
117 | if _, err = w.Write(buf[:8]); err != nil { | |
118 | return | |
119 | } | |
120 | ||
121 | // Write public key algorithm, hash ID, and hash value | |
122 | buf[0] = byte(sig.PubKeyAlgo) | |
123 | hashId, ok := s2k.HashToHashId(sig.Hash) | |
124 | if !ok { | |
125 | return errors.UnsupportedError(fmt.Sprintf("hash function %v", sig.Hash)) | |
126 | } | |
127 | buf[1] = hashId | |
128 | copy(buf[2:4], sig.HashTag[:]) | |
129 | if _, err = w.Write(buf[:4]); err != nil { | |
130 | return | |
131 | } | |
132 | ||
133 | if sig.RSASignature.bytes == nil && sig.DSASigR.bytes == nil { | |
134 | return errors.InvalidArgumentError("Signature: need to call Sign, SignUserId or SignKey before Serialize") | |
135 | } | |
136 | ||
137 | switch sig.PubKeyAlgo { | |
138 | case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: | |
139 | err = writeMPIs(w, sig.RSASignature) | |
140 | case PubKeyAlgoDSA: | |
141 | err = writeMPIs(w, sig.DSASigR, sig.DSASigS) | |
142 | default: | |
143 | panic("impossible") | |
144 | } | |
145 | return | |
146 | } |