]>
Commit | Line | Data |
---|---|---|
c680a8e1 RS |
1 | // Copyright 2011 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 | "bytes" | |
9 | "crypto" | |
10 | "crypto/dsa" | |
11 | "crypto/ecdsa" | |
12 | "encoding/asn1" | |
13 | "encoding/binary" | |
14 | "hash" | |
15 | "io" | |
16 | "math/big" | |
17 | "strconv" | |
18 | "time" | |
19 | ||
20 | "golang.org/x/crypto/openpgp/errors" | |
21 | "golang.org/x/crypto/openpgp/s2k" | |
22 | ) | |
23 | ||
24 | const ( | |
25 | // See RFC 4880, section 5.2.3.21 for details. | |
26 | KeyFlagCertify = 1 << iota | |
27 | KeyFlagSign | |
28 | KeyFlagEncryptCommunications | |
29 | KeyFlagEncryptStorage | |
30 | ) | |
31 | ||
32 | // Signature represents a signature. See RFC 4880, section 5.2. | |
33 | type Signature struct { | |
34 | SigType SignatureType | |
35 | PubKeyAlgo PublicKeyAlgorithm | |
36 | Hash crypto.Hash | |
37 | ||
38 | // HashSuffix is extra data that is hashed in after the signed data. | |
39 | HashSuffix []byte | |
40 | // HashTag contains the first two bytes of the hash for fast rejection | |
41 | // of bad signed data. | |
42 | HashTag [2]byte | |
43 | CreationTime time.Time | |
44 | ||
45 | RSASignature parsedMPI | |
46 | DSASigR, DSASigS parsedMPI | |
47 | ECDSASigR, ECDSASigS parsedMPI | |
48 | ||
49 | // rawSubpackets contains the unparsed subpackets, in order. | |
50 | rawSubpackets []outputSubpacket | |
51 | ||
52 | // The following are optional so are nil when not included in the | |
53 | // signature. | |
54 | ||
55 | SigLifetimeSecs, KeyLifetimeSecs *uint32 | |
56 | PreferredSymmetric, PreferredHash, PreferredCompression []uint8 | |
57 | IssuerKeyId *uint64 | |
58 | IsPrimaryId *bool | |
59 | ||
60 | // FlagsValid is set if any flags were given. See RFC 4880, section | |
61 | // 5.2.3.21 for details. | |
62 | FlagsValid bool | |
63 | FlagCertify, FlagSign, FlagEncryptCommunications, FlagEncryptStorage bool | |
64 | ||
65 | // RevocationReason is set if this signature has been revoked. | |
66 | // See RFC 4880, section 5.2.3.23 for details. | |
67 | RevocationReason *uint8 | |
68 | RevocationReasonText string | |
69 | ||
70 | // MDC is set if this signature has a feature packet that indicates | |
71 | // support for MDC subpackets. | |
72 | MDC bool | |
73 | ||
74 | // EmbeddedSignature, if non-nil, is a signature of the parent key, by | |
75 | // this key. This prevents an attacker from claiming another's signing | |
76 | // subkey as their own. | |
77 | EmbeddedSignature *Signature | |
78 | ||
79 | outSubpackets []outputSubpacket | |
80 | } | |
81 | ||
82 | func (sig *Signature) parse(r io.Reader) (err error) { | |
83 | // RFC 4880, section 5.2.3 | |
84 | var buf [5]byte | |
85 | _, err = readFull(r, buf[:1]) | |
86 | if err != nil { | |
87 | return | |
88 | } | |
89 | if buf[0] != 4 { | |
90 | err = errors.UnsupportedError("signature packet version " + strconv.Itoa(int(buf[0]))) | |
91 | return | |
92 | } | |
93 | ||
94 | _, err = readFull(r, buf[:5]) | |
95 | if err != nil { | |
96 | return | |
97 | } | |
98 | sig.SigType = SignatureType(buf[0]) | |
99 | sig.PubKeyAlgo = PublicKeyAlgorithm(buf[1]) | |
100 | switch sig.PubKeyAlgo { | |
101 | case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA, PubKeyAlgoECDSA: | |
102 | default: | |
103 | err = errors.UnsupportedError("public key algorithm " + strconv.Itoa(int(sig.PubKeyAlgo))) | |
104 | return | |
105 | } | |
106 | ||
107 | var ok bool | |
108 | sig.Hash, ok = s2k.HashIdToHash(buf[2]) | |
109 | if !ok { | |
110 | return errors.UnsupportedError("hash function " + strconv.Itoa(int(buf[2]))) | |
111 | } | |
112 | ||
113 | hashedSubpacketsLength := int(buf[3])<<8 | int(buf[4]) | |
114 | l := 6 + hashedSubpacketsLength | |
115 | sig.HashSuffix = make([]byte, l+6) | |
116 | sig.HashSuffix[0] = 4 | |
117 | copy(sig.HashSuffix[1:], buf[:5]) | |
118 | hashedSubpackets := sig.HashSuffix[6:l] | |
119 | _, err = readFull(r, hashedSubpackets) | |
120 | if err != nil { | |
121 | return | |
122 | } | |
123 | // See RFC 4880, section 5.2.4 | |
124 | trailer := sig.HashSuffix[l:] | |
125 | trailer[0] = 4 | |
126 | trailer[1] = 0xff | |
127 | trailer[2] = uint8(l >> 24) | |
128 | trailer[3] = uint8(l >> 16) | |
129 | trailer[4] = uint8(l >> 8) | |
130 | trailer[5] = uint8(l) | |
131 | ||
132 | err = parseSignatureSubpackets(sig, hashedSubpackets, true) | |
133 | if err != nil { | |
134 | return | |
135 | } | |
136 | ||
137 | _, err = readFull(r, buf[:2]) | |
138 | if err != nil { | |
139 | return | |
140 | } | |
141 | unhashedSubpacketsLength := int(buf[0])<<8 | int(buf[1]) | |
142 | unhashedSubpackets := make([]byte, unhashedSubpacketsLength) | |
143 | _, err = readFull(r, unhashedSubpackets) | |
144 | if err != nil { | |
145 | return | |
146 | } | |
147 | err = parseSignatureSubpackets(sig, unhashedSubpackets, false) | |
148 | if err != nil { | |
149 | return | |
150 | } | |
151 | ||
152 | _, err = readFull(r, sig.HashTag[:2]) | |
153 | if err != nil { | |
154 | return | |
155 | } | |
156 | ||
157 | switch sig.PubKeyAlgo { | |
158 | case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: | |
159 | sig.RSASignature.bytes, sig.RSASignature.bitLength, err = readMPI(r) | |
160 | case PubKeyAlgoDSA: | |
161 | sig.DSASigR.bytes, sig.DSASigR.bitLength, err = readMPI(r) | |
162 | if err == nil { | |
163 | sig.DSASigS.bytes, sig.DSASigS.bitLength, err = readMPI(r) | |
164 | } | |
165 | case PubKeyAlgoECDSA: | |
166 | sig.ECDSASigR.bytes, sig.ECDSASigR.bitLength, err = readMPI(r) | |
167 | if err == nil { | |
168 | sig.ECDSASigS.bytes, sig.ECDSASigS.bitLength, err = readMPI(r) | |
169 | } | |
170 | default: | |
171 | panic("unreachable") | |
172 | } | |
173 | return | |
174 | } | |
175 | ||
176 | // parseSignatureSubpackets parses subpackets of the main signature packet. See | |
177 | // RFC 4880, section 5.2.3.1. | |
178 | func parseSignatureSubpackets(sig *Signature, subpackets []byte, isHashed bool) (err error) { | |
179 | for len(subpackets) > 0 { | |
180 | subpackets, err = parseSignatureSubpacket(sig, subpackets, isHashed) | |
181 | if err != nil { | |
182 | return | |
183 | } | |
184 | } | |
185 | ||
186 | if sig.CreationTime.IsZero() { | |
187 | err = errors.StructuralError("no creation time in signature") | |
188 | } | |
189 | ||
190 | return | |
191 | } | |
192 | ||
193 | type signatureSubpacketType uint8 | |
194 | ||
195 | const ( | |
196 | creationTimeSubpacket signatureSubpacketType = 2 | |
197 | signatureExpirationSubpacket signatureSubpacketType = 3 | |
198 | keyExpirationSubpacket signatureSubpacketType = 9 | |
199 | prefSymmetricAlgosSubpacket signatureSubpacketType = 11 | |
200 | issuerSubpacket signatureSubpacketType = 16 | |
201 | prefHashAlgosSubpacket signatureSubpacketType = 21 | |
202 | prefCompressionSubpacket signatureSubpacketType = 22 | |
203 | primaryUserIdSubpacket signatureSubpacketType = 25 | |
204 | keyFlagsSubpacket signatureSubpacketType = 27 | |
205 | reasonForRevocationSubpacket signatureSubpacketType = 29 | |
206 | featuresSubpacket signatureSubpacketType = 30 | |
207 | embeddedSignatureSubpacket signatureSubpacketType = 32 | |
208 | ) | |
209 | ||
210 | // parseSignatureSubpacket parses a single subpacket. len(subpacket) is >= 1. | |
211 | func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (rest []byte, err error) { | |
212 | // RFC 4880, section 5.2.3.1 | |
213 | var ( | |
214 | length uint32 | |
215 | packetType signatureSubpacketType | |
216 | isCritical bool | |
217 | ) | |
218 | switch { | |
219 | case subpacket[0] < 192: | |
220 | length = uint32(subpacket[0]) | |
221 | subpacket = subpacket[1:] | |
222 | case subpacket[0] < 255: | |
223 | if len(subpacket) < 2 { | |
224 | goto Truncated | |
225 | } | |
226 | length = uint32(subpacket[0]-192)<<8 + uint32(subpacket[1]) + 192 | |
227 | subpacket = subpacket[2:] | |
228 | default: | |
229 | if len(subpacket) < 5 { | |
230 | goto Truncated | |
231 | } | |
232 | length = uint32(subpacket[1])<<24 | | |
233 | uint32(subpacket[2])<<16 | | |
234 | uint32(subpacket[3])<<8 | | |
235 | uint32(subpacket[4]) | |
236 | subpacket = subpacket[5:] | |
237 | } | |
238 | if length > uint32(len(subpacket)) { | |
239 | goto Truncated | |
240 | } | |
241 | rest = subpacket[length:] | |
242 | subpacket = subpacket[:length] | |
243 | if len(subpacket) == 0 { | |
244 | err = errors.StructuralError("zero length signature subpacket") | |
245 | return | |
246 | } | |
247 | packetType = signatureSubpacketType(subpacket[0] & 0x7f) | |
248 | isCritical = subpacket[0]&0x80 == 0x80 | |
249 | subpacket = subpacket[1:] | |
250 | sig.rawSubpackets = append(sig.rawSubpackets, outputSubpacket{isHashed, packetType, isCritical, subpacket}) | |
251 | switch packetType { | |
252 | case creationTimeSubpacket: | |
253 | if !isHashed { | |
254 | err = errors.StructuralError("signature creation time in non-hashed area") | |
255 | return | |
256 | } | |
257 | if len(subpacket) != 4 { | |
258 | err = errors.StructuralError("signature creation time not four bytes") | |
259 | return | |
260 | } | |
261 | t := binary.BigEndian.Uint32(subpacket) | |
262 | sig.CreationTime = time.Unix(int64(t), 0) | |
263 | case signatureExpirationSubpacket: | |
264 | // Signature expiration time, section 5.2.3.10 | |
265 | if !isHashed { | |
266 | return | |
267 | } | |
268 | if len(subpacket) != 4 { | |
269 | err = errors.StructuralError("expiration subpacket with bad length") | |
270 | return | |
271 | } | |
272 | sig.SigLifetimeSecs = new(uint32) | |
273 | *sig.SigLifetimeSecs = binary.BigEndian.Uint32(subpacket) | |
274 | case keyExpirationSubpacket: | |
275 | // Key expiration time, section 5.2.3.6 | |
276 | if !isHashed { | |
277 | return | |
278 | } | |
279 | if len(subpacket) != 4 { | |
280 | err = errors.StructuralError("key expiration subpacket with bad length") | |
281 | return | |
282 | } | |
283 | sig.KeyLifetimeSecs = new(uint32) | |
284 | *sig.KeyLifetimeSecs = binary.BigEndian.Uint32(subpacket) | |
285 | case prefSymmetricAlgosSubpacket: | |
286 | // Preferred symmetric algorithms, section 5.2.3.7 | |
287 | if !isHashed { | |
288 | return | |
289 | } | |
290 | sig.PreferredSymmetric = make([]byte, len(subpacket)) | |
291 | copy(sig.PreferredSymmetric, subpacket) | |
292 | case issuerSubpacket: | |
293 | // Issuer, section 5.2.3.5 | |
294 | if len(subpacket) != 8 { | |
295 | err = errors.StructuralError("issuer subpacket with bad length") | |
296 | return | |
297 | } | |
298 | sig.IssuerKeyId = new(uint64) | |
299 | *sig.IssuerKeyId = binary.BigEndian.Uint64(subpacket) | |
300 | case prefHashAlgosSubpacket: | |
301 | // Preferred hash algorithms, section 5.2.3.8 | |
302 | if !isHashed { | |
303 | return | |
304 | } | |
305 | sig.PreferredHash = make([]byte, len(subpacket)) | |
306 | copy(sig.PreferredHash, subpacket) | |
307 | case prefCompressionSubpacket: | |
308 | // Preferred compression algorithms, section 5.2.3.9 | |
309 | if !isHashed { | |
310 | return | |
311 | } | |
312 | sig.PreferredCompression = make([]byte, len(subpacket)) | |
313 | copy(sig.PreferredCompression, subpacket) | |
314 | case primaryUserIdSubpacket: | |
315 | // Primary User ID, section 5.2.3.19 | |
316 | if !isHashed { | |
317 | return | |
318 | } | |
319 | if len(subpacket) != 1 { | |
320 | err = errors.StructuralError("primary user id subpacket with bad length") | |
321 | return | |
322 | } | |
323 | sig.IsPrimaryId = new(bool) | |
324 | if subpacket[0] > 0 { | |
325 | *sig.IsPrimaryId = true | |
326 | } | |
327 | case keyFlagsSubpacket: | |
328 | // Key flags, section 5.2.3.21 | |
329 | if !isHashed { | |
330 | return | |
331 | } | |
332 | if len(subpacket) == 0 { | |
333 | err = errors.StructuralError("empty key flags subpacket") | |
334 | return | |
335 | } | |
336 | sig.FlagsValid = true | |
337 | if subpacket[0]&KeyFlagCertify != 0 { | |
338 | sig.FlagCertify = true | |
339 | } | |
340 | if subpacket[0]&KeyFlagSign != 0 { | |
341 | sig.FlagSign = true | |
342 | } | |
343 | if subpacket[0]&KeyFlagEncryptCommunications != 0 { | |
344 | sig.FlagEncryptCommunications = true | |
345 | } | |
346 | if subpacket[0]&KeyFlagEncryptStorage != 0 { | |
347 | sig.FlagEncryptStorage = true | |
348 | } | |
349 | case reasonForRevocationSubpacket: | |
350 | // Reason For Revocation, section 5.2.3.23 | |
351 | if !isHashed { | |
352 | return | |
353 | } | |
354 | if len(subpacket) == 0 { | |
355 | err = errors.StructuralError("empty revocation reason subpacket") | |
356 | return | |
357 | } | |
358 | sig.RevocationReason = new(uint8) | |
359 | *sig.RevocationReason = subpacket[0] | |
360 | sig.RevocationReasonText = string(subpacket[1:]) | |
361 | case featuresSubpacket: | |
362 | // Features subpacket, section 5.2.3.24 specifies a very general | |
363 | // mechanism for OpenPGP implementations to signal support for new | |
364 | // features. In practice, the subpacket is used exclusively to | |
365 | // indicate support for MDC-protected encryption. | |
366 | sig.MDC = len(subpacket) >= 1 && subpacket[0]&1 == 1 | |
367 | case embeddedSignatureSubpacket: | |
368 | // Only usage is in signatures that cross-certify | |
369 | // signing subkeys. section 5.2.3.26 describes the | |
370 | // format, with its usage described in section 11.1 | |
371 | if sig.EmbeddedSignature != nil { | |
372 | err = errors.StructuralError("Cannot have multiple embedded signatures") | |
373 | return | |
374 | } | |
375 | sig.EmbeddedSignature = new(Signature) | |
376 | // Embedded signatures are required to be v4 signatures see | |
377 | // section 12.1. However, we only parse v4 signatures in this | |
378 | // file anyway. | |
379 | if err := sig.EmbeddedSignature.parse(bytes.NewBuffer(subpacket)); err != nil { | |
380 | return nil, err | |
381 | } | |
382 | if sigType := sig.EmbeddedSignature.SigType; sigType != SigTypePrimaryKeyBinding { | |
383 | return nil, errors.StructuralError("cross-signature has unexpected type " + strconv.Itoa(int(sigType))) | |
384 | } | |
385 | default: | |
386 | if isCritical { | |
387 | err = errors.UnsupportedError("unknown critical signature subpacket type " + strconv.Itoa(int(packetType))) | |
388 | return | |
389 | } | |
390 | } | |
391 | return | |
392 | ||
393 | Truncated: | |
394 | err = errors.StructuralError("signature subpacket truncated") | |
395 | return | |
396 | } | |
397 | ||
398 | // subpacketLengthLength returns the length, in bytes, of an encoded length value. | |
399 | func subpacketLengthLength(length int) int { | |
400 | if length < 192 { | |
401 | return 1 | |
402 | } | |
403 | if length < 16320 { | |
404 | return 2 | |
405 | } | |
406 | return 5 | |
407 | } | |
408 | ||
409 | // serializeSubpacketLength marshals the given length into to. | |
410 | func serializeSubpacketLength(to []byte, length int) int { | |
411 | // RFC 4880, Section 4.2.2. | |
412 | if length < 192 { | |
413 | to[0] = byte(length) | |
414 | return 1 | |
415 | } | |
416 | if length < 16320 { | |
417 | length -= 192 | |
418 | to[0] = byte((length >> 8) + 192) | |
419 | to[1] = byte(length) | |
420 | return 2 | |
421 | } | |
422 | to[0] = 255 | |
423 | to[1] = byte(length >> 24) | |
424 | to[2] = byte(length >> 16) | |
425 | to[3] = byte(length >> 8) | |
426 | to[4] = byte(length) | |
427 | return 5 | |
428 | } | |
429 | ||
430 | // subpacketsLength returns the serialized length, in bytes, of the given | |
431 | // subpackets. | |
432 | func subpacketsLength(subpackets []outputSubpacket, hashed bool) (length int) { | |
433 | for _, subpacket := range subpackets { | |
434 | if subpacket.hashed == hashed { | |
435 | length += subpacketLengthLength(len(subpacket.contents) + 1) | |
436 | length += 1 // type byte | |
437 | length += len(subpacket.contents) | |
438 | } | |
439 | } | |
440 | return | |
441 | } | |
442 | ||
443 | // serializeSubpackets marshals the given subpackets into to. | |
444 | func serializeSubpackets(to []byte, subpackets []outputSubpacket, hashed bool) { | |
445 | for _, subpacket := range subpackets { | |
446 | if subpacket.hashed == hashed { | |
447 | n := serializeSubpacketLength(to, len(subpacket.contents)+1) | |
448 | to[n] = byte(subpacket.subpacketType) | |
449 | to = to[1+n:] | |
450 | n = copy(to, subpacket.contents) | |
451 | to = to[n:] | |
452 | } | |
453 | } | |
454 | return | |
455 | } | |
456 | ||
457 | // KeyExpired returns whether sig is a self-signature of a key that has | |
458 | // expired. | |
459 | func (sig *Signature) KeyExpired(currentTime time.Time) bool { | |
460 | if sig.KeyLifetimeSecs == nil { | |
461 | return false | |
462 | } | |
463 | expiry := sig.CreationTime.Add(time.Duration(*sig.KeyLifetimeSecs) * time.Second) | |
464 | return currentTime.After(expiry) | |
465 | } | |
466 | ||
467 | // buildHashSuffix constructs the HashSuffix member of sig in preparation for signing. | |
468 | func (sig *Signature) buildHashSuffix() (err error) { | |
469 | hashedSubpacketsLen := subpacketsLength(sig.outSubpackets, true) | |
470 | ||
471 | var ok bool | |
472 | l := 6 + hashedSubpacketsLen | |
473 | sig.HashSuffix = make([]byte, l+6) | |
474 | sig.HashSuffix[0] = 4 | |
475 | sig.HashSuffix[1] = uint8(sig.SigType) | |
476 | sig.HashSuffix[2] = uint8(sig.PubKeyAlgo) | |
477 | sig.HashSuffix[3], ok = s2k.HashToHashId(sig.Hash) | |
478 | if !ok { | |
479 | sig.HashSuffix = nil | |
480 | return errors.InvalidArgumentError("hash cannot be represented in OpenPGP: " + strconv.Itoa(int(sig.Hash))) | |
481 | } | |
482 | sig.HashSuffix[4] = byte(hashedSubpacketsLen >> 8) | |
483 | sig.HashSuffix[5] = byte(hashedSubpacketsLen) | |
484 | serializeSubpackets(sig.HashSuffix[6:l], sig.outSubpackets, true) | |
485 | trailer := sig.HashSuffix[l:] | |
486 | trailer[0] = 4 | |
487 | trailer[1] = 0xff | |
488 | trailer[2] = byte(l >> 24) | |
489 | trailer[3] = byte(l >> 16) | |
490 | trailer[4] = byte(l >> 8) | |
491 | trailer[5] = byte(l) | |
492 | return | |
493 | } | |
494 | ||
495 | func (sig *Signature) signPrepareHash(h hash.Hash) (digest []byte, err error) { | |
496 | err = sig.buildHashSuffix() | |
497 | if err != nil { | |
498 | return | |
499 | } | |
500 | ||
501 | h.Write(sig.HashSuffix) | |
502 | digest = h.Sum(nil) | |
503 | copy(sig.HashTag[:], digest) | |
504 | return | |
505 | } | |
506 | ||
507 | // Sign signs a message with a private key. The hash, h, must contain | |
508 | // the hash of the message to be signed and will be mutated by this function. | |
509 | // On success, the signature is stored in sig. Call Serialize to write it out. | |
510 | // If config is nil, sensible defaults will be used. | |
511 | func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey, config *Config) (err error) { | |
512 | sig.outSubpackets = sig.buildSubpackets() | |
513 | digest, err := sig.signPrepareHash(h) | |
514 | if err != nil { | |
515 | return | |
516 | } | |
517 | ||
518 | switch priv.PubKeyAlgo { | |
519 | case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: | |
520 | // supports both *rsa.PrivateKey and crypto.Signer | |
521 | sig.RSASignature.bytes, err = priv.PrivateKey.(crypto.Signer).Sign(config.Random(), digest, sig.Hash) | |
522 | sig.RSASignature.bitLength = uint16(8 * len(sig.RSASignature.bytes)) | |
523 | case PubKeyAlgoDSA: | |
524 | dsaPriv := priv.PrivateKey.(*dsa.PrivateKey) | |
525 | ||
526 | // Need to truncate hashBytes to match FIPS 186-3 section 4.6. | |
527 | subgroupSize := (dsaPriv.Q.BitLen() + 7) / 8 | |
528 | if len(digest) > subgroupSize { | |
529 | digest = digest[:subgroupSize] | |
530 | } | |
531 | r, s, err := dsa.Sign(config.Random(), dsaPriv, digest) | |
532 | if err == nil { | |
533 | sig.DSASigR.bytes = r.Bytes() | |
534 | sig.DSASigR.bitLength = uint16(8 * len(sig.DSASigR.bytes)) | |
535 | sig.DSASigS.bytes = s.Bytes() | |
536 | sig.DSASigS.bitLength = uint16(8 * len(sig.DSASigS.bytes)) | |
537 | } | |
538 | case PubKeyAlgoECDSA: | |
539 | var r, s *big.Int | |
540 | if pk, ok := priv.PrivateKey.(*ecdsa.PrivateKey); ok { | |
541 | // direct support, avoid asn1 wrapping/unwrapping | |
542 | r, s, err = ecdsa.Sign(config.Random(), pk, digest) | |
543 | } else { | |
544 | var b []byte | |
107c1cdb | 545 | b, err = priv.PrivateKey.(crypto.Signer).Sign(config.Random(), digest, sig.Hash) |
c680a8e1 RS |
546 | if err == nil { |
547 | r, s, err = unwrapECDSASig(b) | |
548 | } | |
549 | } | |
550 | if err == nil { | |
551 | sig.ECDSASigR = fromBig(r) | |
552 | sig.ECDSASigS = fromBig(s) | |
553 | } | |
554 | default: | |
555 | err = errors.UnsupportedError("public key algorithm: " + strconv.Itoa(int(sig.PubKeyAlgo))) | |
556 | } | |
557 | ||
558 | return | |
559 | } | |
560 | ||
561 | // unwrapECDSASig parses the two integer components of an ASN.1-encoded ECDSA | |
562 | // signature. | |
563 | func unwrapECDSASig(b []byte) (r, s *big.Int, err error) { | |
564 | var ecsdaSig struct { | |
565 | R, S *big.Int | |
566 | } | |
567 | _, err = asn1.Unmarshal(b, &ecsdaSig) | |
568 | if err != nil { | |
569 | return | |
570 | } | |
571 | return ecsdaSig.R, ecsdaSig.S, nil | |
572 | } | |
573 | ||
574 | // SignUserId computes a signature from priv, asserting that pub is a valid | |
575 | // key for the identity id. On success, the signature is stored in sig. Call | |
576 | // Serialize to write it out. | |
577 | // If config is nil, sensible defaults will be used. | |
578 | func (sig *Signature) SignUserId(id string, pub *PublicKey, priv *PrivateKey, config *Config) error { | |
579 | h, err := userIdSignatureHash(id, pub, sig.Hash) | |
580 | if err != nil { | |
581 | return err | |
582 | } | |
583 | return sig.Sign(h, priv, config) | |
584 | } | |
585 | ||
586 | // SignKey computes a signature from priv, asserting that pub is a subkey. On | |
587 | // success, the signature is stored in sig. Call Serialize to write it out. | |
588 | // If config is nil, sensible defaults will be used. | |
589 | func (sig *Signature) SignKey(pub *PublicKey, priv *PrivateKey, config *Config) error { | |
590 | h, err := keySignatureHash(&priv.PublicKey, pub, sig.Hash) | |
591 | if err != nil { | |
592 | return err | |
593 | } | |
594 | return sig.Sign(h, priv, config) | |
595 | } | |
596 | ||
597 | // Serialize marshals sig to w. Sign, SignUserId or SignKey must have been | |
598 | // called first. | |
599 | func (sig *Signature) Serialize(w io.Writer) (err error) { | |
600 | if len(sig.outSubpackets) == 0 { | |
601 | sig.outSubpackets = sig.rawSubpackets | |
602 | } | |
603 | if sig.RSASignature.bytes == nil && sig.DSASigR.bytes == nil && sig.ECDSASigR.bytes == nil { | |
604 | return errors.InvalidArgumentError("Signature: need to call Sign, SignUserId or SignKey before Serialize") | |
605 | } | |
606 | ||
607 | sigLength := 0 | |
608 | switch sig.PubKeyAlgo { | |
609 | case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: | |
610 | sigLength = 2 + len(sig.RSASignature.bytes) | |
611 | case PubKeyAlgoDSA: | |
612 | sigLength = 2 + len(sig.DSASigR.bytes) | |
613 | sigLength += 2 + len(sig.DSASigS.bytes) | |
614 | case PubKeyAlgoECDSA: | |
615 | sigLength = 2 + len(sig.ECDSASigR.bytes) | |
616 | sigLength += 2 + len(sig.ECDSASigS.bytes) | |
617 | default: | |
618 | panic("impossible") | |
619 | } | |
620 | ||
621 | unhashedSubpacketsLen := subpacketsLength(sig.outSubpackets, false) | |
622 | length := len(sig.HashSuffix) - 6 /* trailer not included */ + | |
623 | 2 /* length of unhashed subpackets */ + unhashedSubpacketsLen + | |
624 | 2 /* hash tag */ + sigLength | |
625 | err = serializeHeader(w, packetTypeSignature, length) | |
626 | if err != nil { | |
627 | return | |
628 | } | |
629 | ||
630 | _, err = w.Write(sig.HashSuffix[:len(sig.HashSuffix)-6]) | |
631 | if err != nil { | |
632 | return | |
633 | } | |
634 | ||
635 | unhashedSubpackets := make([]byte, 2+unhashedSubpacketsLen) | |
636 | unhashedSubpackets[0] = byte(unhashedSubpacketsLen >> 8) | |
637 | unhashedSubpackets[1] = byte(unhashedSubpacketsLen) | |
638 | serializeSubpackets(unhashedSubpackets[2:], sig.outSubpackets, false) | |
639 | ||
640 | _, err = w.Write(unhashedSubpackets) | |
641 | if err != nil { | |
642 | return | |
643 | } | |
644 | _, err = w.Write(sig.HashTag[:]) | |
645 | if err != nil { | |
646 | return | |
647 | } | |
648 | ||
649 | switch sig.PubKeyAlgo { | |
650 | case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: | |
651 | err = writeMPIs(w, sig.RSASignature) | |
652 | case PubKeyAlgoDSA: | |
653 | err = writeMPIs(w, sig.DSASigR, sig.DSASigS) | |
654 | case PubKeyAlgoECDSA: | |
655 | err = writeMPIs(w, sig.ECDSASigR, sig.ECDSASigS) | |
656 | default: | |
657 | panic("impossible") | |
658 | } | |
659 | return | |
660 | } | |
661 | ||
662 | // outputSubpacket represents a subpacket to be marshaled. | |
663 | type outputSubpacket struct { | |
664 | hashed bool // true if this subpacket is in the hashed area. | |
665 | subpacketType signatureSubpacketType | |
666 | isCritical bool | |
667 | contents []byte | |
668 | } | |
669 | ||
670 | func (sig *Signature) buildSubpackets() (subpackets []outputSubpacket) { | |
671 | creationTime := make([]byte, 4) | |
672 | binary.BigEndian.PutUint32(creationTime, uint32(sig.CreationTime.Unix())) | |
673 | subpackets = append(subpackets, outputSubpacket{true, creationTimeSubpacket, false, creationTime}) | |
674 | ||
675 | if sig.IssuerKeyId != nil { | |
676 | keyId := make([]byte, 8) | |
677 | binary.BigEndian.PutUint64(keyId, *sig.IssuerKeyId) | |
678 | subpackets = append(subpackets, outputSubpacket{true, issuerSubpacket, false, keyId}) | |
679 | } | |
680 | ||
681 | if sig.SigLifetimeSecs != nil && *sig.SigLifetimeSecs != 0 { | |
682 | sigLifetime := make([]byte, 4) | |
683 | binary.BigEndian.PutUint32(sigLifetime, *sig.SigLifetimeSecs) | |
684 | subpackets = append(subpackets, outputSubpacket{true, signatureExpirationSubpacket, true, sigLifetime}) | |
685 | } | |
686 | ||
687 | // Key flags may only appear in self-signatures or certification signatures. | |
688 | ||
689 | if sig.FlagsValid { | |
690 | var flags byte | |
691 | if sig.FlagCertify { | |
692 | flags |= KeyFlagCertify | |
693 | } | |
694 | if sig.FlagSign { | |
695 | flags |= KeyFlagSign | |
696 | } | |
697 | if sig.FlagEncryptCommunications { | |
698 | flags |= KeyFlagEncryptCommunications | |
699 | } | |
700 | if sig.FlagEncryptStorage { | |
701 | flags |= KeyFlagEncryptStorage | |
702 | } | |
703 | subpackets = append(subpackets, outputSubpacket{true, keyFlagsSubpacket, false, []byte{flags}}) | |
704 | } | |
705 | ||
706 | // The following subpackets may only appear in self-signatures | |
707 | ||
708 | if sig.KeyLifetimeSecs != nil && *sig.KeyLifetimeSecs != 0 { | |
709 | keyLifetime := make([]byte, 4) | |
710 | binary.BigEndian.PutUint32(keyLifetime, *sig.KeyLifetimeSecs) | |
711 | subpackets = append(subpackets, outputSubpacket{true, keyExpirationSubpacket, true, keyLifetime}) | |
712 | } | |
713 | ||
714 | if sig.IsPrimaryId != nil && *sig.IsPrimaryId { | |
715 | subpackets = append(subpackets, outputSubpacket{true, primaryUserIdSubpacket, false, []byte{1}}) | |
716 | } | |
717 | ||
718 | if len(sig.PreferredSymmetric) > 0 { | |
719 | subpackets = append(subpackets, outputSubpacket{true, prefSymmetricAlgosSubpacket, false, sig.PreferredSymmetric}) | |
720 | } | |
721 | ||
722 | if len(sig.PreferredHash) > 0 { | |
723 | subpackets = append(subpackets, outputSubpacket{true, prefHashAlgosSubpacket, false, sig.PreferredHash}) | |
724 | } | |
725 | ||
726 | if len(sig.PreferredCompression) > 0 { | |
727 | subpackets = append(subpackets, outputSubpacket{true, prefCompressionSubpacket, false, sig.PreferredCompression}) | |
728 | } | |
729 | ||
730 | return | |
731 | } |