aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/crypto
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2011-09-16 15:47:21 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2011-09-16 15:47:21 +0000
commitadb0401dac41c81571722312d4586b2693f95aa6 (patch)
treeea2b52e3c258d6b6d9356977c683c7f72a4a5fd5 /libgo/go/crypto
parent5548ca3540bccbc908a45942896d635ea5f1c23f (diff)
downloadgcc-adb0401dac41c81571722312d4586b2693f95aa6.zip
gcc-adb0401dac41c81571722312d4586b2693f95aa6.tar.gz
gcc-adb0401dac41c81571722312d4586b2693f95aa6.tar.bz2
Update Go library to r60.
From-SVN: r178910
Diffstat (limited to 'libgo/go/crypto')
-rw-r--r--libgo/go/crypto/aes/cipher.go4
-rw-r--r--libgo/go/crypto/blowfish/cipher.go4
-rw-r--r--libgo/go/crypto/cast5/cast5.go2
-rw-r--r--libgo/go/crypto/cipher/ocfb.go8
-rw-r--r--libgo/go/crypto/dsa/dsa.go4
-rw-r--r--libgo/go/crypto/elliptic/elliptic.go2
-rw-r--r--libgo/go/crypto/elliptic/elliptic_test.go4
-rw-r--r--libgo/go/crypto/hmac/hmac_test.go2
-rw-r--r--libgo/go/crypto/ocsp/ocsp.go38
-rw-r--r--libgo/go/crypto/openpgp/armor/armor.go2
-rw-r--r--libgo/go/crypto/openpgp/canonical_text_test.go1
-rw-r--r--libgo/go/crypto/openpgp/elgamal/elgamal.go122
-rw-r--r--libgo/go/crypto/openpgp/elgamal/elgamal_test.go49
-rw-r--r--libgo/go/crypto/openpgp/keys.go248
-rw-r--r--libgo/go/crypto/openpgp/packet/encrypted_key.go132
-rw-r--r--libgo/go/crypto/openpgp/packet/encrypted_key_test.go85
-rw-r--r--libgo/go/crypto/openpgp/packet/literal.go37
-rw-r--r--libgo/go/crypto/openpgp/packet/one_pass_signature.go27
-rw-r--r--libgo/go/crypto/openpgp/packet/packet.go110
-rw-r--r--libgo/go/crypto/openpgp/packet/packet_test.go44
-rw-r--r--libgo/go/crypto/openpgp/packet/private_key.go108
-rw-r--r--libgo/go/crypto/openpgp/packet/private_key_test.go64
-rw-r--r--libgo/go/crypto/openpgp/packet/public_key.go154
-rw-r--r--libgo/go/crypto/openpgp/packet/public_key_test.go36
-rw-r--r--libgo/go/crypto/openpgp/packet/signature.go110
-rw-r--r--libgo/go/crypto/openpgp/packet/signature_test.go22
-rw-r--r--libgo/go/crypto/openpgp/packet/symmetric_key_encrypted.go66
-rw-r--r--libgo/go/crypto/openpgp/packet/symmetric_key_encrypted_test.go39
-rw-r--r--libgo/go/crypto/openpgp/packet/symmetrically_encrypted.go95
-rw-r--r--libgo/go/crypto/openpgp/packet/symmetrically_encrypted_test.go46
-rw-r--r--libgo/go/crypto/openpgp/packet/userid.go56
-rw-r--r--libgo/go/crypto/openpgp/packet/userid_test.go45
-rw-r--r--libgo/go/crypto/openpgp/read.go24
-rw-r--r--libgo/go/crypto/openpgp/read_test.go125
-rw-r--r--libgo/go/crypto/openpgp/s2k/s2k.go22
-rw-r--r--libgo/go/crypto/openpgp/s2k/s2k_test.go25
-rw-r--r--libgo/go/crypto/openpgp/write.go236
-rw-r--r--libgo/go/crypto/openpgp/write_test.go187
-rw-r--r--libgo/go/crypto/rand/rand_windows.go2
-rw-r--r--libgo/go/crypto/rand/util.go80
-rw-r--r--libgo/go/crypto/rsa/pkcs1v15.go4
-rw-r--r--libgo/go/crypto/rsa/rsa.go100
-rw-r--r--libgo/go/crypto/subtle/constant_time_test.go4
-rw-r--r--libgo/go/crypto/tls/common.go2
-rw-r--r--libgo/go/crypto/tls/conn.go10
-rw-r--r--libgo/go/crypto/tls/generate_cert.go10
-rw-r--r--libgo/go/crypto/tls/handshake_client.go6
-rw-r--r--libgo/go/crypto/tls/handshake_server.go10
-rw-r--r--libgo/go/crypto/tls/handshake_server_test.go1
-rw-r--r--libgo/go/crypto/tls/key_agreement.go42
-rw-r--r--libgo/go/crypto/tls/tls.go8
-rw-r--r--libgo/go/crypto/twofish/twofish.go4
-rw-r--r--libgo/go/crypto/x509/cert_pool.go3
-rw-r--r--libgo/go/crypto/x509/pkix/pkix.go167
-rw-r--r--libgo/go/crypto/x509/verify.go11
-rw-r--r--libgo/go/crypto/x509/verify_test.go13
-rw-r--r--libgo/go/crypto/x509/x509.go552
-rw-r--r--libgo/go/crypto/x509/x509_test.go188
-rw-r--r--libgo/go/crypto/xtea/block.go2
-rw-r--r--libgo/go/crypto/xtea/cipher.go4
-rw-r--r--libgo/go/crypto/xtea/xtea_test.go10
61 files changed, 2967 insertions, 651 deletions
diff --git a/libgo/go/crypto/aes/cipher.go b/libgo/go/crypto/aes/cipher.go
index 3a9d023..7322353 100644
--- a/libgo/go/crypto/aes/cipher.go
+++ b/libgo/go/crypto/aes/cipher.go
@@ -45,14 +45,14 @@ func NewCipher(key []byte) (*Cipher, os.Error) {
// BlockSize returns the AES block size, 16 bytes.
// It is necessary to satisfy the Cipher interface in the
-// package "crypto/block".
+// package "crypto/cipher".
func (c *Cipher) BlockSize() int { return BlockSize }
// Encrypt encrypts the 16-byte buffer src using the key k
// and stores the result in dst.
// Note that for amounts of data larger than a block,
// it is not safe to just call Encrypt on successive blocks;
-// instead, use an encryption mode like CBC (see crypto/block/cbc.go).
+// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go).
func (c *Cipher) Encrypt(dst, src []byte) { encryptBlock(c.enc, dst, src) }
// Decrypt decrypts the 16-byte buffer src using the key k
diff --git a/libgo/go/crypto/blowfish/cipher.go b/libgo/go/crypto/blowfish/cipher.go
index f3c5175..6c37dfe 100644
--- a/libgo/go/crypto/blowfish/cipher.go
+++ b/libgo/go/crypto/blowfish/cipher.go
@@ -42,14 +42,14 @@ func NewCipher(key []byte) (*Cipher, os.Error) {
// BlockSize returns the Blowfish block size, 8 bytes.
// It is necessary to satisfy the Cipher interface in the
-// package "crypto/block".
+// package "crypto/cipher".
func (c *Cipher) BlockSize() int { return BlockSize }
// Encrypt encrypts the 8-byte buffer src using the key k
// and stores the result in dst.
// Note that for amounts of data larger than a block,
// it is not safe to just call Encrypt on successive blocks;
-// instead, use an encryption mode like CBC (see crypto/block/cbc.go).
+// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go).
func (c *Cipher) Encrypt(dst, src []byte) {
l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
diff --git a/libgo/go/crypto/cast5/cast5.go b/libgo/go/crypto/cast5/cast5.go
index cb62e31..e9d4a24 100644
--- a/libgo/go/crypto/cast5/cast5.go
+++ b/libgo/go/crypto/cast5/cast5.go
@@ -20,7 +20,7 @@ type Cipher struct {
func NewCipher(key []byte) (c *Cipher, err os.Error) {
if len(key) != KeySize {
- return nil, os.ErrorString("CAST5: keys must be 16 bytes")
+ return nil, os.NewError("CAST5: keys must be 16 bytes")
}
c = new(Cipher)
diff --git a/libgo/go/crypto/cipher/ocfb.go b/libgo/go/crypto/cipher/ocfb.go
index b2d8775..031e74a 100644
--- a/libgo/go/crypto/cipher/ocfb.go
+++ b/libgo/go/crypto/cipher/ocfb.go
@@ -80,9 +80,10 @@ type ocfbDecrypter struct {
// NewOCFBDecrypter returns a Stream which decrypts data with OpenPGP's cipher
// feedback mode using the given Block. Prefix must be the first blockSize + 2
// bytes of the ciphertext, where blockSize is the Block's block size. If an
-// incorrect key is detected then nil is returned. Resync determines if the
-// "resynchronization step" from RFC 4880, 13.9 step 7 is performed. Different
-// parts of OpenPGP vary on this point.
+// incorrect key is detected then nil is returned. On successful exit,
+// blockSize+2 bytes of decrypted data are written into prefix. Resync
+// determines if the "resynchronization step" from RFC 4880, 13.9 step 7 is
+// performed. Different parts of OpenPGP vary on this point.
func NewOCFBDecrypter(block Block, prefix []byte, resync OCFBResyncOption) Stream {
blockSize := block.BlockSize()
if len(prefix) != blockSize+2 {
@@ -118,6 +119,7 @@ func NewOCFBDecrypter(block Block, prefix []byte, resync OCFBResyncOption) Strea
x.fre[1] = prefix[blockSize+1]
x.outUsed = 2
}
+ copy(prefix, prefixCopy)
return x
}
diff --git a/libgo/go/crypto/dsa/dsa.go b/libgo/go/crypto/dsa/dsa.go
index f0af8bb..a5f96fe 100644
--- a/libgo/go/crypto/dsa/dsa.go
+++ b/libgo/go/crypto/dsa/dsa.go
@@ -79,7 +79,7 @@ func GenerateParameters(params *Parameters, rand io.Reader, sizes ParameterSizes
L = 3072
N = 256
default:
- return os.ErrorString("crypto/dsa: invalid ParameterSizes")
+ return os.NewError("crypto/dsa: invalid ParameterSizes")
}
qBytes := make([]byte, N/8)
@@ -158,7 +158,7 @@ GeneratePrimes:
// PrivateKey must already be valid (see GenerateParameters).
func GenerateKey(priv *PrivateKey, rand io.Reader) os.Error {
if priv.P == nil || priv.Q == nil || priv.G == nil {
- return os.ErrorString("crypto/dsa: parameters not set up before generating key")
+ return os.NewError("crypto/dsa: parameters not set up before generating key")
}
x := new(big.Int)
diff --git a/libgo/go/crypto/elliptic/elliptic.go b/libgo/go/crypto/elliptic/elliptic.go
index 335c964..41835f1 100644
--- a/libgo/go/crypto/elliptic/elliptic.go
+++ b/libgo/go/crypto/elliptic/elliptic.go
@@ -284,7 +284,7 @@ func (curve *Curve) Marshal(x, y *big.Int) []byte {
return ret
}
-// Unmarshal converts a point, serialised by Marshal, into an x, y pair. On
+// Unmarshal converts a point, serialized by Marshal, into an x, y pair. On
// error, x = nil.
func (curve *Curve) Unmarshal(data []byte) (x, y *big.Int) {
byteLen := (curve.BitSize + 7) >> 3
diff --git a/libgo/go/crypto/elliptic/elliptic_test.go b/libgo/go/crypto/elliptic/elliptic_test.go
index 02083a9..b7e7f03 100644
--- a/libgo/go/crypto/elliptic/elliptic_test.go
+++ b/libgo/go/crypto/elliptic/elliptic_test.go
@@ -321,8 +321,8 @@ func TestMarshal(t *testing.T) {
t.Error(err)
return
}
- serialised := p224.Marshal(x, y)
- xx, yy := p224.Unmarshal(serialised)
+ serialized := p224.Marshal(x, y)
+ xx, yy := p224.Unmarshal(serialized)
if xx == nil {
t.Error("failed to unmarshal")
return
diff --git a/libgo/go/crypto/hmac/hmac_test.go b/libgo/go/crypto/hmac/hmac_test.go
index 40adbad..bcae63b 100644
--- a/libgo/go/crypto/hmac/hmac_test.go
+++ b/libgo/go/crypto/hmac/hmac_test.go
@@ -190,7 +190,7 @@ func TestHMAC(t *testing.T) {
continue
}
- // Repetive Sum() calls should return the same value
+ // Repetitive Sum() calls should return the same value
for k := 0; k < 2; k++ {
sum := fmt.Sprintf("%x", h.Sum())
if sum != tt.out {
diff --git a/libgo/go/crypto/ocsp/ocsp.go b/libgo/go/crypto/ocsp/ocsp.go
index acd75b8..7ea7a1e 100644
--- a/libgo/go/crypto/ocsp/ocsp.go
+++ b/libgo/go/crypto/ocsp/ocsp.go
@@ -13,6 +13,7 @@ import (
"crypto/rsa"
_ "crypto/sha1"
"crypto/x509"
+ "crypto/x509/pkix"
"os"
"time"
)
@@ -32,21 +33,8 @@ const (
ocspUnauthorized = 5
)
-type rdnSequence []relativeDistinguishedNameSET
-
-type relativeDistinguishedNameSET []attributeTypeAndValue
-
-type attributeTypeAndValue struct {
- Type asn1.ObjectIdentifier
- Value interface{}
-}
-
-type algorithmIdentifier struct {
- Algorithm asn1.ObjectIdentifier
-}
-
type certID struct {
- HashAlgorithm algorithmIdentifier
+ HashAlgorithm pkix.AlgorithmIdentifier
NameHash []byte
IssuerKeyHash []byte
SerialNumber asn1.RawValue
@@ -54,7 +42,7 @@ type certID struct {
type responseASN1 struct {
Status asn1.Enumerated
- Response responseBytes "explicit,tag:0"
+ Response responseBytes `asn1:"explicit,tag:0"`
}
type responseBytes struct {
@@ -64,32 +52,32 @@ type responseBytes struct {
type basicResponse struct {
TBSResponseData responseData
- SignatureAlgorithm algorithmIdentifier
+ SignatureAlgorithm pkix.AlgorithmIdentifier
Signature asn1.BitString
- Certificates []asn1.RawValue "explicit,tag:0,optional"
+ Certificates []asn1.RawValue `asn1:"explicit,tag:0,optional"`
}
type responseData struct {
Raw asn1.RawContent
- Version int "optional,default:1,explicit,tag:0"
- RequestorName rdnSequence "optional,explicit,tag:1"
- KeyHash []byte "optional,explicit,tag:2"
+ Version int `asn1:"optional,default:1,explicit,tag:0"`
+ RequestorName pkix.RDNSequence `asn1:"optional,explicit,tag:1"`
+ KeyHash []byte `asn1:"optional,explicit,tag:2"`
ProducedAt *time.Time
Responses []singleResponse
}
type singleResponse struct {
CertID certID
- Good asn1.Flag "explicit,tag:0,optional"
- Revoked revokedInfo "explicit,tag:1,optional"
- Unknown asn1.Flag "explicit,tag:2,optional"
+ Good asn1.Flag `asn1:"explicit,tag:0,optional"`
+ Revoked revokedInfo `asn1:"explicit,tag:1,optional"`
+ Unknown asn1.Flag `asn1:"explicit,tag:2,optional"`
ThisUpdate *time.Time
- NextUpdate *time.Time "explicit,tag:0,optional"
+ NextUpdate *time.Time `asn1:"explicit,tag:0,optional"`
}
type revokedInfo struct {
RevocationTime *time.Time
- Reason int "explicit,tag:0,optional"
+ Reason int `asn1:"explicit,tag:0,optional"`
}
// This is the exposed reflection of the internal OCSP structures.
diff --git a/libgo/go/crypto/openpgp/armor/armor.go b/libgo/go/crypto/openpgp/armor/armor.go
index 8da612c..9c4180d 100644
--- a/libgo/go/crypto/openpgp/armor/armor.go
+++ b/libgo/go/crypto/openpgp/armor/armor.go
@@ -153,7 +153,7 @@ func (r *openpgpReader) Read(p []byte) (n int, err os.Error) {
// Decode reads a PGP armored block from the given Reader. It will ignore
// leading garbage. If it doesn't find a block, it will return nil, os.EOF. The
-// given Reader is not usable after calling this function: an arbitary amount
+// given Reader is not usable after calling this function: an arbitrary amount
// of data may have been read past the end of the block.
func Decode(in io.Reader) (p *Block, err os.Error) {
r, _ := bufio.NewReaderSize(in, 100)
diff --git a/libgo/go/crypto/openpgp/canonical_text_test.go b/libgo/go/crypto/openpgp/canonical_text_test.go
index 69ecf91..ccf2910 100644
--- a/libgo/go/crypto/openpgp/canonical_text_test.go
+++ b/libgo/go/crypto/openpgp/canonical_text_test.go
@@ -30,7 +30,6 @@ func (r recordingHash) Size() int {
panic("shouldn't be called")
}
-
func testCanonicalText(t *testing.T, input, expected string) {
r := recordingHash{bytes.NewBuffer(nil)}
c := NewCanonicalTextHash(r)
diff --git a/libgo/go/crypto/openpgp/elgamal/elgamal.go b/libgo/go/crypto/openpgp/elgamal/elgamal.go
new file mode 100644
index 0000000..99a6e3e
--- /dev/null
+++ b/libgo/go/crypto/openpgp/elgamal/elgamal.go
@@ -0,0 +1,122 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package elgamal implements ElGamal encryption, suitable for OpenPGP,
+// as specified in "A Public-Key Cryptosystem and a Signature Scheme Based on
+// Discrete Logarithms," IEEE Transactions on Information Theory, v. IT-31,
+// n. 4, 1985, pp. 469-472.
+//
+// This form of ElGamal embeds PKCS#1 v1.5 padding, which may make it
+// unsuitable for other protocols. RSA should be used in preference in any
+// case.
+package elgamal
+
+import (
+ "big"
+ "crypto/rand"
+ "crypto/subtle"
+ "io"
+ "os"
+)
+
+// PublicKey represents an ElGamal public key.
+type PublicKey struct {
+ G, P, Y *big.Int
+}
+
+// PrivateKey represents an ElGamal private key.
+type PrivateKey struct {
+ PublicKey
+ X *big.Int
+}
+
+// Encrypt encrypts the given message to the given public key. The result is a
+// pair of integers. Errors can result from reading random, or because msg is
+// too large to be encrypted to the public key.
+func Encrypt(random io.Reader, pub *PublicKey, msg []byte) (c1, c2 *big.Int, err os.Error) {
+ pLen := (pub.P.BitLen() + 7) / 8
+ if len(msg) > pLen-11 {
+ err = os.NewError("elgamal: message too long")
+ return
+ }
+
+ // EM = 0x02 || PS || 0x00 || M
+ em := make([]byte, pLen-1)
+ em[0] = 2
+ ps, mm := em[1:len(em)-len(msg)-1], em[len(em)-len(msg):]
+ err = nonZeroRandomBytes(ps, random)
+ if err != nil {
+ return
+ }
+ em[len(em)-len(msg)-1] = 0
+ copy(mm, msg)
+
+ m := new(big.Int).SetBytes(em)
+
+ k, err := rand.Int(random, pub.P)
+ if err != nil {
+ return
+ }
+
+ c1 = new(big.Int).Exp(pub.G, k, pub.P)
+ s := new(big.Int).Exp(pub.Y, k, pub.P)
+ c2 = s.Mul(s, m)
+ c2.Mod(c2, pub.P)
+
+ return
+}
+
+// Decrypt takes two integers, resulting from an ElGamal encryption, and
+// returns the plaintext of the message. An error can result only if the
+// ciphertext is invalid. Users should keep in mind that this is a padding
+// oracle and thus, if exposed to an adaptive chosen ciphertext attack, can
+// be used to break the cryptosystem. See ``Chosen Ciphertext Attacks
+// Against Protocols Based on the RSA Encryption Standard PKCS #1'', Daniel
+// Bleichenbacher, Advances in Cryptology (Crypto '98),
+func Decrypt(priv *PrivateKey, c1, c2 *big.Int) (msg []byte, err os.Error) {
+ s := new(big.Int).Exp(c1, priv.X, priv.P)
+ s.ModInverse(s, priv.P)
+ s.Mul(s, c2)
+ s.Mod(s, priv.P)
+ em := s.Bytes()
+
+ firstByteIsTwo := subtle.ConstantTimeByteEq(em[0], 2)
+
+ // The remainder of the plaintext must be a string of non-zero random
+ // octets, followed by a 0, followed by the message.
+ // lookingForIndex: 1 iff we are still looking for the zero.
+ // index: the offset of the first zero byte.
+ var lookingForIndex, index int
+ lookingForIndex = 1
+
+ for i := 1; i < len(em); i++ {
+ equals0 := subtle.ConstantTimeByteEq(em[i], 0)
+ index = subtle.ConstantTimeSelect(lookingForIndex&equals0, i, index)
+ lookingForIndex = subtle.ConstantTimeSelect(equals0, 0, lookingForIndex)
+ }
+
+ if firstByteIsTwo != 1 || lookingForIndex != 0 || index < 9 {
+ return nil, os.NewError("elgamal: decryption error")
+ }
+ return em[index+1:], nil
+}
+
+// nonZeroRandomBytes fills the given slice with non-zero random octets.
+func nonZeroRandomBytes(s []byte, rand io.Reader) (err os.Error) {
+ _, err = io.ReadFull(rand, s)
+ if err != nil {
+ return
+ }
+
+ for i := 0; i < len(s); i++ {
+ for s[i] == 0 {
+ _, err = io.ReadFull(rand, s[i:i+1])
+ if err != nil {
+ return
+ }
+ }
+ }
+
+ return
+}
diff --git a/libgo/go/crypto/openpgp/elgamal/elgamal_test.go b/libgo/go/crypto/openpgp/elgamal/elgamal_test.go
new file mode 100644
index 0000000..101121a
--- /dev/null
+++ b/libgo/go/crypto/openpgp/elgamal/elgamal_test.go
@@ -0,0 +1,49 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package elgamal
+
+import (
+ "big"
+ "bytes"
+ "crypto/rand"
+ "testing"
+)
+
+// This is the 1024-bit MODP group from RFC 5114, section 2.1:
+const primeHex = "B10B8F96A080E01DDE92DE5EAE5D54EC52C99FBCFB06A3C69A6A9DCA52D23B616073E28675A23D189838EF1E2EE652C013ECB4AEA906112324975C3CD49B83BFACCBDD7D90C4BD7098488E9C219A73724EFFD6FAE5644738FAA31A4FF55BCCC0A151AF5F0DC8B4BD45BF37DF365C1A65E68CFDA76D4DA708DF1FB2BC2E4A4371"
+
+const generatorHex = "A4D1CBD5C3FD34126765A442EFB99905F8104DD258AC507FD6406CFF14266D31266FEA1E5C41564B777E690F5504F213160217B4B01B886A5E91547F9E2749F4D7FBD7D3B9A92EE1909D0D2263F80A76A6A24C087A091F531DBF0A0169B6A28AD662A4D18E73AFA32D779D5918D08BC8858F4DCEF97C2A24855E6EEB22B3B2E5"
+
+func fromHex(hex string) *big.Int {
+ n, ok := new(big.Int).SetString(hex, 16)
+ if !ok {
+ panic("failed to parse hex number")
+ }
+ return n
+}
+
+func TestEncryptDecrypt(t *testing.T) {
+ priv := &PrivateKey{
+ PublicKey: PublicKey{
+ G: fromHex(generatorHex),
+ P: fromHex(primeHex),
+ },
+ X: fromHex("42"),
+ }
+ priv.Y = new(big.Int).Exp(priv.G, priv.X, priv.P)
+
+ message := []byte("hello world")
+ c1, c2, err := Encrypt(rand.Reader, &priv.PublicKey, message)
+ if err != nil {
+ t.Errorf("error encrypting: %s", err)
+ }
+ message2, err := Decrypt(priv, c1, c2)
+ if err != nil {
+ t.Errorf("error decrypting: %s", err)
+ }
+ if !bytes.Equal(message2, message) {
+ t.Errorf("decryption failed, got: %x, want: %x", message2, message)
+ }
+}
diff --git a/libgo/go/crypto/openpgp/keys.go b/libgo/go/crypto/openpgp/keys.go
index 6c03f88..c70fb79 100644
--- a/libgo/go/crypto/openpgp/keys.go
+++ b/libgo/go/crypto/openpgp/keys.go
@@ -5,11 +5,14 @@
package openpgp
import (
+ "crypto"
"crypto/openpgp/armor"
"crypto/openpgp/error"
"crypto/openpgp/packet"
+ "crypto/rsa"
"io"
"os"
+ "time"
)
// PublicKeyType is the armor type for a PGP public key.
@@ -62,6 +65,78 @@ type KeyRing interface {
DecryptionKeys() []Key
}
+// primaryIdentity returns the Identity marked as primary or the first identity
+// if none are so marked.
+func (e *Entity) primaryIdentity() *Identity {
+ var firstIdentity *Identity
+ for _, ident := range e.Identities {
+ if firstIdentity == nil {
+ firstIdentity = ident
+ }
+ if ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId {
+ return ident
+ }
+ }
+ return firstIdentity
+}
+
+// encryptionKey returns the best candidate Key for encrypting a message to the
+// given Entity.
+func (e *Entity) encryptionKey() Key {
+ candidateSubkey := -1
+
+ for i, subkey := range e.Subkeys {
+ if subkey.Sig.FlagsValid && subkey.Sig.FlagEncryptCommunications && subkey.PublicKey.PubKeyAlgo.CanEncrypt() {
+ candidateSubkey = i
+ break
+ }
+ }
+
+ i := e.primaryIdentity()
+
+ if e.PrimaryKey.PubKeyAlgo.CanEncrypt() {
+ // If we don't have any candidate subkeys for encryption and
+ // the primary key doesn't have any usage metadata then we
+ // assume that the primary key is ok. Or, if the primary key is
+ // marked as ok to encrypt to, then we can obviously use it.
+ if candidateSubkey == -1 && !i.SelfSignature.FlagsValid || i.SelfSignature.FlagEncryptCommunications && i.SelfSignature.FlagsValid {
+ return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature}
+ }
+ }
+
+ if candidateSubkey != -1 {
+ subkey := e.Subkeys[candidateSubkey]
+ return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig}
+ }
+
+ // This Entity appears to be signing only.
+ return Key{}
+}
+
+// signingKey return the best candidate Key for signing a message with this
+// Entity.
+func (e *Entity) signingKey() Key {
+ candidateSubkey := -1
+
+ for i, subkey := range e.Subkeys {
+ if subkey.Sig.FlagsValid && subkey.Sig.FlagSign && subkey.PublicKey.PubKeyAlgo.CanSign() {
+ candidateSubkey = i
+ break
+ }
+ }
+
+ i := e.primaryIdentity()
+
+ // If we have no candidate subkey then we assume that it's ok to sign
+ // with the primary key.
+ if candidateSubkey == -1 || i.SelfSignature.FlagsValid && i.SelfSignature.FlagSign {
+ return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature}
+ }
+
+ subkey := e.Subkeys[candidateSubkey]
+ return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig}
+}
+
// An EntityList contains one or more Entities.
type EntityList []*Entity
@@ -197,6 +272,10 @@ func readEntity(packets *packet.Reader) (*Entity, os.Error) {
}
}
+ if !e.PrimaryKey.PubKeyAlgo.CanSign() {
+ return nil, error.StructuralError("primary key cannot be used for signatures")
+ }
+
var current *Identity
EachPacket:
for {
@@ -227,7 +306,7 @@ EachPacket:
return nil, error.StructuralError("user ID packet not followed by self-signature")
}
- if sig.SigType == packet.SigTypePositiveCert && sig.IssuerKeyId != nil && *sig.IssuerKeyId == e.PrimaryKey.KeyId {
+ if (sig.SigType == packet.SigTypePositiveCert || sig.SigType == packet.SigTypeGenericCert) && sig.IssuerKeyId != nil && *sig.IssuerKeyId == e.PrimaryKey.KeyId {
if err = e.PrimaryKey.VerifyUserIdSignature(pkt.Id, sig); err != nil {
return nil, error.StructuralError("user ID self-signature invalid: " + err.String())
}
@@ -297,3 +376,170 @@ func addSubkey(e *Entity, packets *packet.Reader, pub *packet.PublicKey, priv *p
e.Subkeys = append(e.Subkeys, subKey)
return nil
}
+
+const defaultRSAKeyBits = 2048
+
+// NewEntity returns an Entity that contains a fresh RSA/RSA keypair with a
+// single identity composed of the given full name, comment and email, any of
+// which may be empty but must not contain any of "()<>\x00".
+func NewEntity(rand io.Reader, currentTimeSecs int64, name, comment, email string) (*Entity, os.Error) {
+ uid := packet.NewUserId(name, comment, email)
+ if uid == nil {
+ return nil, error.InvalidArgumentError("user id field contained invalid characters")
+ }
+ signingPriv, err := rsa.GenerateKey(rand, defaultRSAKeyBits)
+ if err != nil {
+ return nil, err
+ }
+ encryptingPriv, err := rsa.GenerateKey(rand, defaultRSAKeyBits)
+ if err != nil {
+ return nil, err
+ }
+
+ t := uint32(currentTimeSecs)
+
+ e := &Entity{
+ PrimaryKey: packet.NewRSAPublicKey(t, &signingPriv.PublicKey, false /* not a subkey */ ),
+ PrivateKey: packet.NewRSAPrivateKey(t, signingPriv, false /* not a subkey */ ),
+ Identities: make(map[string]*Identity),
+ }
+ isPrimaryId := true
+ e.Identities[uid.Id] = &Identity{
+ Name: uid.Name,
+ UserId: uid,
+ SelfSignature: &packet.Signature{
+ CreationTime: t,
+ SigType: packet.SigTypePositiveCert,
+ PubKeyAlgo: packet.PubKeyAlgoRSA,
+ Hash: crypto.SHA256,
+ IsPrimaryId: &isPrimaryId,
+ FlagsValid: true,
+ FlagSign: true,
+ FlagCertify: true,
+ IssuerKeyId: &e.PrimaryKey.KeyId,
+ },
+ }
+
+ e.Subkeys = make([]Subkey, 1)
+ e.Subkeys[0] = Subkey{
+ PublicKey: packet.NewRSAPublicKey(t, &encryptingPriv.PublicKey, true /* is a subkey */ ),
+ PrivateKey: packet.NewRSAPrivateKey(t, encryptingPriv, true /* is a subkey */ ),
+ Sig: &packet.Signature{
+ CreationTime: t,
+ SigType: packet.SigTypeSubkeyBinding,
+ PubKeyAlgo: packet.PubKeyAlgoRSA,
+ Hash: crypto.SHA256,
+ FlagsValid: true,
+ FlagEncryptStorage: true,
+ FlagEncryptCommunications: true,
+ IssuerKeyId: &e.PrimaryKey.KeyId,
+ },
+ }
+
+ return e, nil
+}
+
+// SerializePrivate serializes an Entity, including private key material, to
+// the given Writer. For now, it must only be used on an Entity returned from
+// NewEntity.
+func (e *Entity) SerializePrivate(w io.Writer) (err os.Error) {
+ err = e.PrivateKey.Serialize(w)
+ if err != nil {
+ return
+ }
+ for _, ident := range e.Identities {
+ err = ident.UserId.Serialize(w)
+ if err != nil {
+ return
+ }
+ err = ident.SelfSignature.SignUserId(ident.UserId.Id, e.PrimaryKey, e.PrivateKey)
+ if err != nil {
+ return
+ }
+ err = ident.SelfSignature.Serialize(w)
+ if err != nil {
+ return
+ }
+ }
+ for _, subkey := range e.Subkeys {
+ err = subkey.PrivateKey.Serialize(w)
+ if err != nil {
+ return
+ }
+ err = subkey.Sig.SignKey(subkey.PublicKey, e.PrivateKey)
+ if err != nil {
+ return
+ }
+ err = subkey.Sig.Serialize(w)
+ if err != nil {
+ return
+ }
+ }
+ return nil
+}
+
+// Serialize writes the public part of the given Entity to w. (No private
+// key material will be output).
+func (e *Entity) Serialize(w io.Writer) os.Error {
+ err := e.PrimaryKey.Serialize(w)
+ if err != nil {
+ return err
+ }
+ for _, ident := range e.Identities {
+ err = ident.UserId.Serialize(w)
+ if err != nil {
+ return err
+ }
+ err = ident.SelfSignature.Serialize(w)
+ if err != nil {
+ return err
+ }
+ for _, sig := range ident.Signatures {
+ err = sig.Serialize(w)
+ if err != nil {
+ return err
+ }
+ }
+ }
+ for _, subkey := range e.Subkeys {
+ err = subkey.PublicKey.Serialize(w)
+ if err != nil {
+ return err
+ }
+ err = subkey.Sig.Serialize(w)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// SignIdentity adds a signature to e, from signer, attesting that identity is
+// associated with e. The provided identity must already be an element of
+// e.Identities and the private key of signer must have been decrypted if
+// necessary.
+func (e *Entity) SignIdentity(identity string, signer *Entity) os.Error {
+ if signer.PrivateKey == nil {
+ return error.InvalidArgumentError("signing Entity must have a private key")
+ }
+ if signer.PrivateKey.Encrypted {
+ return error.InvalidArgumentError("signing Entity's private key must be decrypted")
+ }
+ ident, ok := e.Identities[identity]
+ if !ok {
+ return error.InvalidArgumentError("given identity string not found in Entity")
+ }
+
+ sig := &packet.Signature{
+ SigType: packet.SigTypeGenericCert,
+ PubKeyAlgo: signer.PrivateKey.PubKeyAlgo,
+ Hash: crypto.SHA256,
+ CreationTime: uint32(time.Seconds()),
+ IssuerKeyId: &signer.PrivateKey.KeyId,
+ }
+ if err := sig.SignKey(e.PrimaryKey, signer.PrivateKey); err != nil {
+ return err
+ }
+ ident.Signatures = append(ident.Signatures, sig)
+ return nil
+}
diff --git a/libgo/go/crypto/openpgp/packet/encrypted_key.go b/libgo/go/crypto/openpgp/packet/encrypted_key.go
index b11a9b8..b4730cb 100644
--- a/libgo/go/crypto/openpgp/packet/encrypted_key.go
+++ b/libgo/go/crypto/openpgp/packet/encrypted_key.go
@@ -5,6 +5,8 @@
package packet
import (
+ "big"
+ "crypto/openpgp/elgamal"
"crypto/openpgp/error"
"crypto/rand"
"crypto/rsa"
@@ -14,14 +16,17 @@ import (
"strconv"
)
+const encryptedKeyVersion = 3
+
// EncryptedKey represents a public-key encrypted session key. See RFC 4880,
// section 5.1.
type EncryptedKey struct {
KeyId uint64
Algo PublicKeyAlgorithm
- Encrypted []byte
CipherFunc CipherFunction // only valid after a successful Decrypt
Key []byte // only valid after a successful Decrypt
+
+ encryptedMPI1, encryptedMPI2 []byte
}
func (e *EncryptedKey) parse(r io.Reader) (err os.Error) {
@@ -30,37 +35,134 @@ func (e *EncryptedKey) parse(r io.Reader) (err os.Error) {
if err != nil {
return
}
- if buf[0] != 3 {
+ if buf[0] != encryptedKeyVersion {
return error.UnsupportedError("unknown EncryptedKey version " + strconv.Itoa(int(buf[0])))
}
e.KeyId = binary.BigEndian.Uint64(buf[1:9])
e.Algo = PublicKeyAlgorithm(buf[9])
- if e.Algo == PubKeyAlgoRSA || e.Algo == PubKeyAlgoRSAEncryptOnly {
- e.Encrypted, _, err = readMPI(r)
+ switch e.Algo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
+ e.encryptedMPI1, _, err = readMPI(r)
+ case PubKeyAlgoElGamal:
+ e.encryptedMPI1, _, err = readMPI(r)
+ if err != nil {
+ return
+ }
+ e.encryptedMPI2, _, err = readMPI(r)
}
_, err = consumeAll(r)
return
}
-// DecryptRSA decrypts an RSA encrypted session key with the given private key.
-func (e *EncryptedKey) DecryptRSA(priv *rsa.PrivateKey) (err os.Error) {
- if e.Algo != PubKeyAlgoRSA && e.Algo != PubKeyAlgoRSAEncryptOnly {
- return error.InvalidArgumentError("EncryptedKey not RSA encrypted")
+func checksumKeyMaterial(key []byte) uint16 {
+ var checksum uint16
+ for _, v := range key {
+ checksum += uint16(v)
}
- b, err := rsa.DecryptPKCS1v15(rand.Reader, priv, e.Encrypted)
+ return checksum
+}
+
+// Decrypt decrypts an encrypted session key with the given private key. The
+// private key must have been decrypted first.
+func (e *EncryptedKey) Decrypt(priv *PrivateKey) os.Error {
+ var err os.Error
+ var b []byte
+
+ // TODO(agl): use session key decryption routines here to avoid
+ // padding oracle attacks.
+ switch priv.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
+ b, err = rsa.DecryptPKCS1v15(rand.Reader, priv.PrivateKey.(*rsa.PrivateKey), e.encryptedMPI1)
+ case PubKeyAlgoElGamal:
+ c1 := new(big.Int).SetBytes(e.encryptedMPI1)
+ c2 := new(big.Int).SetBytes(e.encryptedMPI2)
+ b, err = elgamal.Decrypt(priv.PrivateKey.(*elgamal.PrivateKey), c1, c2)
+ default:
+ err = error.InvalidArgumentError("cannot decrypted encrypted session key with private key of type " + strconv.Itoa(int(priv.PubKeyAlgo)))
+ }
+
if err != nil {
- return
+ return err
}
+
e.CipherFunc = CipherFunction(b[0])
e.Key = b[1 : len(b)-2]
expectedChecksum := uint16(b[len(b)-2])<<8 | uint16(b[len(b)-1])
- var checksum uint16
- for _, v := range e.Key {
- checksum += uint16(v)
- }
+ checksum := checksumKeyMaterial(e.Key)
if checksum != expectedChecksum {
return error.StructuralError("EncryptedKey checksum incorrect")
}
- return
+ return nil
+}
+
+// SerializeEncryptedKey serializes an encrypted key packet to w that contains
+// key, encrypted to pub.
+func SerializeEncryptedKey(w io.Writer, rand io.Reader, pub *PublicKey, cipherFunc CipherFunction, key []byte) os.Error {
+ var buf [10]byte
+ buf[0] = encryptedKeyVersion
+ binary.BigEndian.PutUint64(buf[1:9], pub.KeyId)
+ buf[9] = byte(pub.PubKeyAlgo)
+
+ keyBlock := make([]byte, 1 /* cipher type */ +len(key)+2 /* checksum */ )
+ keyBlock[0] = byte(cipherFunc)
+ copy(keyBlock[1:], key)
+ checksum := checksumKeyMaterial(key)
+ keyBlock[1+len(key)] = byte(checksum >> 8)
+ keyBlock[1+len(key)+1] = byte(checksum)
+
+ switch pub.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
+ return serializeEncryptedKeyRSA(w, rand, buf, pub.PublicKey.(*rsa.PublicKey), keyBlock)
+ case PubKeyAlgoElGamal:
+ return serializeEncryptedKeyElGamal(w, rand, buf, pub.PublicKey.(*elgamal.PublicKey), keyBlock)
+ case PubKeyAlgoDSA, PubKeyAlgoRSASignOnly:
+ return error.InvalidArgumentError("cannot encrypt to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo)))
+ }
+
+ return error.UnsupportedError("encrypting a key to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo)))
+}
+
+func serializeEncryptedKeyRSA(w io.Writer, rand io.Reader, header [10]byte, pub *rsa.PublicKey, keyBlock []byte) os.Error {
+ cipherText, err := rsa.EncryptPKCS1v15(rand, pub, keyBlock)
+ if err != nil {
+ return error.InvalidArgumentError("RSA encryption failed: " + err.String())
+ }
+
+ packetLen := 10 /* header length */ + 2 /* mpi size */ + len(cipherText)
+
+ err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
+ if err != nil {
+ return err
+ }
+ _, err = w.Write(header[:])
+ if err != nil {
+ return err
+ }
+ return writeMPI(w, 8*uint16(len(cipherText)), cipherText)
+}
+
+func serializeEncryptedKeyElGamal(w io.Writer, rand io.Reader, header [10]byte, pub *elgamal.PublicKey, keyBlock []byte) os.Error {
+ c1, c2, err := elgamal.Encrypt(rand, pub, keyBlock)
+ if err != nil {
+ return error.InvalidArgumentError("ElGamal encryption failed: " + err.String())
+ }
+
+ packetLen := 10 /* header length */
+ packetLen += 2 /* mpi size */ + (c1.BitLen()+7)/8
+ packetLen += 2 /* mpi size */ + (c2.BitLen()+7)/8
+
+ err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
+ if err != nil {
+ return err
+ }
+ _, err = w.Write(header[:])
+ if err != nil {
+ return err
+ }
+ err = writeBig(w, c1)
+ if err != nil {
+ return err
+ }
+ return writeBig(w, c2)
}
diff --git a/libgo/go/crypto/openpgp/packet/encrypted_key_test.go b/libgo/go/crypto/openpgp/packet/encrypted_key_test.go
index 755ae7a..b402245 100644
--- a/libgo/go/crypto/openpgp/packet/encrypted_key_test.go
+++ b/libgo/go/crypto/openpgp/packet/encrypted_key_test.go
@@ -6,6 +6,8 @@ package packet
import (
"big"
+ "bytes"
+ "crypto/rand"
"crypto/rsa"
"fmt"
"testing"
@@ -19,7 +21,27 @@ func bigFromBase10(s string) *big.Int {
return b
}
-func TestEncryptedKey(t *testing.T) {
+var encryptedKeyPub = rsa.PublicKey{
+ E: 65537,
+ N: bigFromBase10("115804063926007623305902631768113868327816898845124614648849934718568541074358183759250136204762053879858102352159854352727097033322663029387610959884180306668628526686121021235757016368038585212410610742029286439607686208110250133174279811431933746643015923132833417396844716207301518956640020862630546868823"),
+}
+
+var encryptedKeyRSAPriv = &rsa.PrivateKey{
+ PublicKey: encryptedKeyPub,
+ D: bigFromBase10("32355588668219869544751561565313228297765464314098552250409557267371233892496951383426602439009993875125222579159850054973310859166139474359774543943714622292329487391199285040721944491839695981199720170366763547754915493640685849961780092241140181198779299712578774460837139360803883139311171713302987058393"),
+}
+
+var encryptedKeyPriv = &PrivateKey{
+ PublicKey: PublicKey{
+ PubKeyAlgo: PubKeyAlgoRSA,
+ },
+ PrivateKey: encryptedKeyRSAPriv,
+}
+
+func TestDecryptingEncryptedKey(t *testing.T) {
+ const encryptedKeyHex = "c18c032a67d68660df41c70104005789d0de26b6a50c985a02a13131ca829c413a35d0e6fa8d6842599252162808ac7439c72151c8c6183e76923fe3299301414d0c25a2f06a2257db3839e7df0ec964773f6e4c4ac7ff3b48c444237166dd46ba8ff443a5410dc670cb486672fdbe7c9dfafb75b4fea83af3a204fe2a7dfa86bd20122b4f3d2646cbeecb8f7be8"
+ const expectedKeyHex = "d930363f7e0308c333b9618617ea728963d8df993665ae7be1092d4926fd864b"
+
p, err := Read(readerFromHex(encryptedKeyHex))
if err != nil {
t.Errorf("error from Read: %s", err)
@@ -36,23 +58,63 @@ func TestEncryptedKey(t *testing.T) {
return
}
- pub := rsa.PublicKey{
- E: 65537,
- N: bigFromBase10("115804063926007623305902631768113868327816898845124614648849934718568541074358183759250136204762053879858102352159854352727097033322663029387610959884180306668628526686121021235757016368038585212410610742029286439607686208110250133174279811431933746643015923132833417396844716207301518956640020862630546868823"),
+ err = ek.Decrypt(encryptedKeyPriv)
+ if err != nil {
+ t.Errorf("error from Decrypt: %s", err)
+ return
+ }
+
+ if ek.CipherFunc != CipherAES256 {
+ t.Errorf("unexpected EncryptedKey contents: %#v", ek)
+ return
+ }
+
+ keyHex := fmt.Sprintf("%x", ek.Key)
+ if keyHex != expectedKeyHex {
+ t.Errorf("bad key, got %s want %x", keyHex, expectedKeyHex)
+ }
+}
+
+func TestEncryptingEncryptedKey(t *testing.T) {
+ key := []byte{1, 2, 3, 4}
+ const expectedKeyHex = "01020304"
+ const keyId = 42
+
+ pub := &PublicKey{
+ PublicKey: &encryptedKeyPub,
+ KeyId: keyId,
+ PubKeyAlgo: PubKeyAlgoRSAEncryptOnly,
+ }
+
+ buf := new(bytes.Buffer)
+ err := SerializeEncryptedKey(buf, rand.Reader, pub, CipherAES128, key)
+ if err != nil {
+ t.Errorf("error writing encrypted key packet: %s", err)
+ }
+
+ p, err := Read(buf)
+ if err != nil {
+ t.Errorf("error from Read: %s", err)
+ return
+ }
+ ek, ok := p.(*EncryptedKey)
+ if !ok {
+ t.Errorf("didn't parse an EncryptedKey, got %#v", p)
+ return
}
- priv := &rsa.PrivateKey{
- PublicKey: pub,
- D: bigFromBase10("32355588668219869544751561565313228297765464314098552250409557267371233892496951383426602439009993875125222579159850054973310859166139474359774543943714622292329487391199285040721944491839695981199720170366763547754915493640685849961780092241140181198779299712578774460837139360803883139311171713302987058393"),
+ if ek.KeyId != keyId || ek.Algo != PubKeyAlgoRSAEncryptOnly {
+ t.Errorf("unexpected EncryptedKey contents: %#v", ek)
+ return
}
- err = ek.DecryptRSA(priv)
+ err = ek.Decrypt(encryptedKeyPriv)
if err != nil {
- t.Errorf("error from DecryptRSA: %s", err)
+ t.Errorf("error from Decrypt: %s", err)
return
}
- if ek.CipherFunc != CipherAES256 {
+ if ek.CipherFunc != CipherAES128 {
t.Errorf("unexpected EncryptedKey contents: %#v", ek)
return
}
@@ -62,6 +124,3 @@ func TestEncryptedKey(t *testing.T) {
t.Errorf("bad key, got %s want %x", keyHex, expectedKeyHex)
}
}
-
-const encryptedKeyHex = "c18c032a67d68660df41c70104005789d0de26b6a50c985a02a13131ca829c413a35d0e6fa8d6842599252162808ac7439c72151c8c6183e76923fe3299301414d0c25a2f06a2257db3839e7df0ec964773f6e4c4ac7ff3b48c444237166dd46ba8ff443a5410dc670cb486672fdbe7c9dfafb75b4fea83af3a204fe2a7dfa86bd20122b4f3d2646cbeecb8f7be8"
-const expectedKeyHex = "d930363f7e0308c333b9618617ea728963d8df993665ae7be1092d4926fd864b"
diff --git a/libgo/go/crypto/openpgp/packet/literal.go b/libgo/go/crypto/openpgp/packet/literal.go
index 04f50e5..9411572 100644
--- a/libgo/go/crypto/openpgp/packet/literal.go
+++ b/libgo/go/crypto/openpgp/packet/literal.go
@@ -51,3 +51,40 @@ func (l *LiteralData) parse(r io.Reader) (err os.Error) {
l.Body = r
return
}
+
+// SerializeLiteral serializes a literal data packet to w and returns a
+// WriteCloser to which the data itself can be written and which MUST be closed
+// on completion. The fileName is truncated to 255 bytes.
+func SerializeLiteral(w io.WriteCloser, isBinary bool, fileName string, time uint32) (plaintext io.WriteCloser, err os.Error) {
+ var buf [4]byte
+ buf[0] = 't'
+ if isBinary {
+ buf[0] = 'b'
+ }
+ if len(fileName) > 255 {
+ fileName = fileName[:255]
+ }
+ buf[1] = byte(len(fileName))
+
+ inner, err := serializeStreamHeader(w, packetTypeLiteralData)
+ if err != nil {
+ return
+ }
+
+ _, err = inner.Write(buf[:2])
+ if err != nil {
+ return
+ }
+ _, err = inner.Write([]byte(fileName))
+ if err != nil {
+ return
+ }
+ binary.BigEndian.PutUint32(buf[:], time)
+ _, err = inner.Write(buf[:])
+ if err != nil {
+ return
+ }
+
+ plaintext = inner
+ return
+}
diff --git a/libgo/go/crypto/openpgp/packet/one_pass_signature.go b/libgo/go/crypto/openpgp/packet/one_pass_signature.go
index acbf58b..ca826e4 100644
--- a/libgo/go/crypto/openpgp/packet/one_pass_signature.go
+++ b/libgo/go/crypto/openpgp/packet/one_pass_signature.go
@@ -24,6 +24,8 @@ type OnePassSignature struct {
IsLast bool
}
+const onePassSignatureVersion = 3
+
func (ops *OnePassSignature) parse(r io.Reader) (err os.Error) {
var buf [13]byte
@@ -31,7 +33,7 @@ func (ops *OnePassSignature) parse(r io.Reader) (err os.Error) {
if err != nil {
return
}
- if buf[0] != 3 {
+ if buf[0] != onePassSignatureVersion {
err = error.UnsupportedError("one-pass-signature packet version " + strconv.Itoa(int(buf[0])))
}
@@ -47,3 +49,26 @@ func (ops *OnePassSignature) parse(r io.Reader) (err os.Error) {
ops.IsLast = buf[12] != 0
return
}
+
+// Serialize marshals the given OnePassSignature to w.
+func (ops *OnePassSignature) Serialize(w io.Writer) os.Error {
+ var buf [13]byte
+ buf[0] = onePassSignatureVersion
+ buf[1] = uint8(ops.SigType)
+ var ok bool
+ buf[2], ok = s2k.HashToHashId(ops.Hash)
+ if !ok {
+ return error.UnsupportedError("hash type: " + strconv.Itoa(int(ops.Hash)))
+ }
+ buf[3] = uint8(ops.PubKeyAlgo)
+ binary.BigEndian.PutUint64(buf[4:12], ops.KeyId)
+ if ops.IsLast {
+ buf[12] = 1
+ }
+
+ if err := serializeHeader(w, packetTypeOnePassSignature, len(buf)); err != nil {
+ return err
+ }
+ _, err := w.Write(buf[:])
+ return err
+}
diff --git a/libgo/go/crypto/openpgp/packet/packet.go b/libgo/go/crypto/openpgp/packet/packet.go
index c0ec44d..1d7297e 100644
--- a/libgo/go/crypto/openpgp/packet/packet.go
+++ b/libgo/go/crypto/openpgp/packet/packet.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package packet implements parsing and serialisation of OpenPGP packets, as
+// Package packet implements parsing and serialization of OpenPGP packets, as
// specified in RFC 4880.
package packet
@@ -92,6 +92,46 @@ func (r *partialLengthReader) Read(p []byte) (n int, err os.Error) {
return
}
+// partialLengthWriter writes a stream of data using OpenPGP partial lengths.
+// See RFC 4880, section 4.2.2.4.
+type partialLengthWriter struct {
+ w io.WriteCloser
+ lengthByte [1]byte
+}
+
+func (w *partialLengthWriter) Write(p []byte) (n int, err os.Error) {
+ for len(p) > 0 {
+ for power := uint(14); power < 32; power-- {
+ l := 1 << power
+ if len(p) >= l {
+ w.lengthByte[0] = 224 + uint8(power)
+ _, err = w.w.Write(w.lengthByte[:])
+ if err != nil {
+ return
+ }
+ var m int
+ m, err = w.w.Write(p[:l])
+ n += m
+ if err != nil {
+ return
+ }
+ p = p[l:]
+ break
+ }
+ }
+ }
+ return
+}
+
+func (w *partialLengthWriter) Close() os.Error {
+ w.lengthByte[0] = 0
+ _, err := w.w.Write(w.lengthByte[:])
+ if err != nil {
+ return err
+ }
+ return w.w.Close()
+}
+
// A spanReader is an io.LimitReader, but it returns ErrUnexpectedEOF if the
// underlying Reader returns EOF before the limit has been reached.
type spanReader struct {
@@ -195,6 +235,20 @@ func serializeHeader(w io.Writer, ptype packetType, length int) (err os.Error) {
return
}
+// serializeStreamHeader writes an OpenPGP packet header to w where the
+// length of the packet is unknown. It returns a io.WriteCloser which can be
+// used to write the contents of the packet. See RFC 4880, section 4.2.
+func serializeStreamHeader(w io.WriteCloser, ptype packetType) (out io.WriteCloser, err os.Error) {
+ var buf [1]byte
+ buf[0] = 0x80 | 0x40 | byte(ptype)
+ _, err = w.Write(buf[:])
+ if err != nil {
+ return
+ }
+ out = &partialLengthWriter{w: w}
+ return
+}
+
// Packet represents an OpenPGP packet. Users are expected to try casting
// instances of this interface to specific packet types.
type Packet interface {
@@ -301,12 +355,12 @@ type SignatureType uint8
const (
SigTypeBinary SignatureType = 0
- SigTypeText = 1
- SigTypeGenericCert = 0x10
- SigTypePersonaCert = 0x11
- SigTypeCasualCert = 0x12
- SigTypePositiveCert = 0x13
- SigTypeSubkeyBinding = 0x18
+ SigTypeText = 1
+ SigTypeGenericCert = 0x10
+ SigTypePersonaCert = 0x11
+ SigTypeCasualCert = 0x12
+ SigTypePositiveCert = 0x13
+ SigTypeSubkeyBinding = 0x18
)
// PublicKeyAlgorithm represents the different public key system specified for
@@ -318,23 +372,43 @@ const (
PubKeyAlgoRSA PublicKeyAlgorithm = 1
PubKeyAlgoRSAEncryptOnly PublicKeyAlgorithm = 2
PubKeyAlgoRSASignOnly PublicKeyAlgorithm = 3
- PubKeyAlgoElgamal PublicKeyAlgorithm = 16
+ PubKeyAlgoElGamal PublicKeyAlgorithm = 16
PubKeyAlgoDSA PublicKeyAlgorithm = 17
)
+// CanEncrypt returns true if it's possible to encrypt a message to a public
+// key of the given type.
+func (pka PublicKeyAlgorithm) CanEncrypt() bool {
+ switch pka {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoElGamal:
+ return true
+ }
+ return false
+}
+
+// CanSign returns true if it's possible for a public key of the given type to
+// sign a message.
+func (pka PublicKeyAlgorithm) CanSign() bool {
+ switch pka {
+ case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA:
+ return true
+ }
+ return false
+}
+
// CipherFunction represents the different block ciphers specified for OpenPGP. See
// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-13
type CipherFunction uint8
const (
- CipherCAST5 = 3
- CipherAES128 = 7
- CipherAES192 = 8
- CipherAES256 = 9
+ CipherCAST5 CipherFunction = 3
+ CipherAES128 CipherFunction = 7
+ CipherAES192 CipherFunction = 8
+ CipherAES256 CipherFunction = 9
)
-// keySize returns the key size, in bytes, of cipher.
-func (cipher CipherFunction) keySize() int {
+// KeySize returns the key size, in bytes, of cipher.
+func (cipher CipherFunction) KeySize() int {
switch cipher {
case CipherCAST5:
return cast5.KeySize
@@ -386,6 +460,14 @@ func readMPI(r io.Reader) (mpi []byte, bitLength uint16, err os.Error) {
return
}
+// mpiLength returns the length of the given *big.Int when serialized as an
+// MPI.
+func mpiLength(n *big.Int) (mpiLengthInBytes int) {
+ mpiLengthInBytes = 2 /* MPI length */
+ mpiLengthInBytes += (n.BitLen() + 7) / 8
+ return
+}
+
// writeMPI serializes a big integer to w.
func writeMPI(w io.Writer, bitLength uint16, mpiBytes []byte) (err os.Error) {
_, err = w.Write([]byte{byte(bitLength >> 8), byte(bitLength)})
diff --git a/libgo/go/crypto/openpgp/packet/packet_test.go b/libgo/go/crypto/openpgp/packet/packet_test.go
index 1a4692c..23d9978 100644
--- a/libgo/go/crypto/openpgp/packet/packet_test.go
+++ b/libgo/go/crypto/openpgp/packet/packet_test.go
@@ -210,3 +210,47 @@ func TestSerializeHeader(t *testing.T) {
}
}
}
+
+func TestPartialLengths(t *testing.T) {
+ buf := bytes.NewBuffer(nil)
+ w := new(partialLengthWriter)
+ w.w = noOpCloser{buf}
+
+ const maxChunkSize = 64
+
+ var b [maxChunkSize]byte
+ var n uint8
+ for l := 1; l <= maxChunkSize; l++ {
+ for i := 0; i < l; i++ {
+ b[i] = n
+ n++
+ }
+ m, err := w.Write(b[:l])
+ if m != l {
+ t.Errorf("short write got: %d want: %d", m, l)
+ }
+ if err != nil {
+ t.Errorf("error from write: %s", err)
+ }
+ }
+ w.Close()
+
+ want := (maxChunkSize * (maxChunkSize + 1)) / 2
+ copyBuf := bytes.NewBuffer(nil)
+ r := &partialLengthReader{buf, 0, true}
+ m, err := io.Copy(copyBuf, r)
+ if m != int64(want) {
+ t.Errorf("short copy got: %d want: %d", m, want)
+ }
+ if err != nil {
+ t.Errorf("error from copy: %s", err)
+ }
+
+ copyBytes := copyBuf.Bytes()
+ for i := 0; i < want; i++ {
+ if copyBytes[i] != uint8(i) {
+ t.Errorf("bad pattern in copy at %d", i)
+ break
+ }
+ }
+}
diff --git a/libgo/go/crypto/openpgp/packet/private_key.go b/libgo/go/crypto/openpgp/packet/private_key.go
index fde2a99..6f8133d 100644
--- a/libgo/go/crypto/openpgp/packet/private_key.go
+++ b/libgo/go/crypto/openpgp/packet/private_key.go
@@ -9,6 +9,7 @@ import (
"bytes"
"crypto/cipher"
"crypto/dsa"
+ "crypto/openpgp/elgamal"
"crypto/openpgp/error"
"crypto/openpgp/s2k"
"crypto/rsa"
@@ -32,6 +33,13 @@ type PrivateKey struct {
iv []byte
}
+func NewRSAPrivateKey(currentTimeSecs uint32, priv *rsa.PrivateKey, isSubkey bool) *PrivateKey {
+ pk := new(PrivateKey)
+ pk.PublicKey = *NewRSAPublicKey(currentTimeSecs, &priv.PublicKey, isSubkey)
+ pk.PrivateKey = priv
+ return pk
+}
+
func (pk *PrivateKey) parse(r io.Reader) (err os.Error) {
err = (&pk.PublicKey).parse(r)
if err != nil {
@@ -91,13 +99,90 @@ func (pk *PrivateKey) parse(r io.Reader) (err os.Error) {
return
}
+func mod64kHash(d []byte) uint16 {
+ h := uint16(0)
+ for i := 0; i < len(d); i += 2 {
+ v := uint16(d[i]) << 8
+ if i+1 < len(d) {
+ v += uint16(d[i+1])
+ }
+ h += v
+ }
+ return h
+}
+
+func (pk *PrivateKey) Serialize(w io.Writer) (err os.Error) {
+ // TODO(agl): support encrypted private keys
+ buf := bytes.NewBuffer(nil)
+ err = pk.PublicKey.serializeWithoutHeaders(buf)
+ if err != nil {
+ return
+ }
+ buf.WriteByte(0 /* no encryption */ )
+
+ privateKeyBuf := bytes.NewBuffer(nil)
+
+ switch priv := pk.PrivateKey.(type) {
+ case *rsa.PrivateKey:
+ err = serializeRSAPrivateKey(privateKeyBuf, priv)
+ default:
+ err = error.InvalidArgumentError("non-RSA private key")
+ }
+ if err != nil {
+ return
+ }
+
+ ptype := packetTypePrivateKey
+ contents := buf.Bytes()
+ privateKeyBytes := privateKeyBuf.Bytes()
+ if pk.IsSubkey {
+ ptype = packetTypePrivateSubkey
+ }
+ err = serializeHeader(w, ptype, len(contents)+len(privateKeyBytes)+2)
+ if err != nil {
+ return
+ }
+ _, err = w.Write(contents)
+ if err != nil {
+ return
+ }
+ _, err = w.Write(privateKeyBytes)
+ if err != nil {
+ return
+ }
+
+ checksum := mod64kHash(privateKeyBytes)
+ var checksumBytes [2]byte
+ checksumBytes[0] = byte(checksum >> 8)
+ checksumBytes[1] = byte(checksum)
+ _, err = w.Write(checksumBytes[:])
+
+ return
+}
+
+func serializeRSAPrivateKey(w io.Writer, priv *rsa.PrivateKey) os.Error {
+ err := writeBig(w, priv.D)
+ if err != nil {
+ return err
+ }
+ err = writeBig(w, priv.Primes[1])
+ if err != nil {
+ return err
+ }
+ err = writeBig(w, priv.Primes[0])
+ if err != nil {
+ return err
+ }
+ return writeBig(w, priv.Precomputed.Qinv)
+}
+
// Decrypt decrypts an encrypted private key using a passphrase.
func (pk *PrivateKey) Decrypt(passphrase []byte) os.Error {
if !pk.Encrypted {
return nil
}
- key := make([]byte, pk.cipher.keySize())
+ key := make([]byte, pk.cipher.KeySize())
pk.s2k(key, passphrase)
block := pk.cipher.new(key)
cfb := cipher.NewCFBDecrypter(block, pk.iv)
@@ -140,6 +225,8 @@ func (pk *PrivateKey) parsePrivateKey(data []byte) (err os.Error) {
return pk.parseRSAPrivateKey(data)
case PubKeyAlgoDSA:
return pk.parseDSAPrivateKey(data)
+ case PubKeyAlgoElGamal:
+ return pk.parseElGamalPrivateKey(data)
}
panic("impossible")
}
@@ -193,3 +280,22 @@ func (pk *PrivateKey) parseDSAPrivateKey(data []byte) (err os.Error) {
return nil
}
+
+func (pk *PrivateKey) parseElGamalPrivateKey(data []byte) (err os.Error) {
+ pub := pk.PublicKey.PublicKey.(*elgamal.PublicKey)
+ priv := new(elgamal.PrivateKey)
+ priv.PublicKey = *pub
+
+ buf := bytes.NewBuffer(data)
+ x, _, err := readMPI(buf)
+ if err != nil {
+ return
+ }
+
+ priv.X = new(big.Int).SetBytes(x)
+ pk.PrivateKey = priv
+ pk.Encrypted = false
+ pk.encryptedData = nil
+
+ return nil
+}
diff --git a/libgo/go/crypto/openpgp/packet/private_key_test.go b/libgo/go/crypto/openpgp/packet/private_key_test.go
index e941cc7..60eebaa 100644
--- a/libgo/go/crypto/openpgp/packet/private_key_test.go
+++ b/libgo/go/crypto/openpgp/packet/private_key_test.go
@@ -8,30 +8,50 @@ import (
"testing"
)
-func TestPrivateKeyRead(t *testing.T) {
- packet, err := Read(readerFromHex(privKeyHex))
- if err != nil {
- t.Error(err)
- return
- }
-
- privKey := packet.(*PrivateKey)
-
- if !privKey.Encrypted {
- t.Error("private key isn't encrypted")
- return
- }
-
- err = privKey.Decrypt([]byte("testing"))
- if err != nil {
- t.Error(err)
- return
- }
+var privateKeyTests = []struct {
+ privateKeyHex string
+ creationTime uint32
+}{
+ {
+ privKeyRSAHex,
+ 0x4cc349a8,
+ },
+ {
+ privKeyElGamalHex,
+ 0x4df9ee1a,
+ },
+}
- if privKey.CreationTime != 0x4cc349a8 || privKey.Encrypted {
- t.Errorf("failed to parse, got: %#v", privKey)
+func TestPrivateKeyRead(t *testing.T) {
+ for i, test := range privateKeyTests {
+ packet, err := Read(readerFromHex(test.privateKeyHex))
+ if err != nil {
+ t.Errorf("#%d: failed to parse: %s", i, err)
+ continue
+ }
+
+ privKey := packet.(*PrivateKey)
+
+ if !privKey.Encrypted {
+ t.Errorf("#%d: private key isn't encrypted", i)
+ continue
+ }
+
+ err = privKey.Decrypt([]byte("testing"))
+ if err != nil {
+ t.Errorf("#%d: failed to decrypt: %s", i, err)
+ continue
+ }
+
+ if privKey.CreationTime != test.creationTime || privKey.Encrypted {
+ t.Errorf("#%d: bad result, got: %#v", i, privKey)
+ }
}
}
// Generated with `gpg --export-secret-keys "Test Key 2"`
-const privKeyHex = "9501fe044cc349a8010400b70ca0010e98c090008d45d1ee8f9113bd5861fd57b88bacb7c68658747663f1e1a3b5a98f32fda6472373c024b97359cd2efc88ff60f77751adfbf6af5e615e6a1408cfad8bf0cea30b0d5f53aa27ad59089ba9b15b7ebc2777a25d7b436144027e3bcd203909f147d0e332b240cf63d3395f5dfe0df0a6c04e8655af7eacdf0011010001fe0303024a252e7d475fd445607de39a265472aa74a9320ba2dac395faa687e9e0336aeb7e9a7397e511b5afd9dc84557c80ac0f3d4d7bfec5ae16f20d41c8c84a04552a33870b930420e230e179564f6d19bb153145e76c33ae993886c388832b0fa042ddda7f133924f3854481533e0ede31d51278c0519b29abc3bf53da673e13e3e1214b52413d179d7f66deee35cac8eacb060f78379d70ef4af8607e68131ff529439668fc39c9ce6dfef8a5ac234d234802cbfb749a26107db26406213ae5c06d4673253a3cbee1fcbae58d6ab77e38d6e2c0e7c6317c48e054edadb5a40d0d48acb44643d998139a8a66bb820be1f3f80185bc777d14b5954b60effe2448a036d565c6bc0b915fcea518acdd20ab07bc1529f561c58cd044f723109b93f6fd99f876ff891d64306b5d08f48bab59f38695e9109c4dec34013ba3153488ce070268381ba923ee1eb77125b36afcb4347ec3478c8f2735b06ef17351d872e577fa95d0c397c88c71b59629a36aec"
+const privKeyRSAHex = "9501fe044cc349a8010400b70ca0010e98c090008d45d1ee8f9113bd5861fd57b88bacb7c68658747663f1e1a3b5a98f32fda6472373c024b97359cd2efc88ff60f77751adfbf6af5e615e6a1408cfad8bf0cea30b0d5f53aa27ad59089ba9b15b7ebc2777a25d7b436144027e3bcd203909f147d0e332b240cf63d3395f5dfe0df0a6c04e8655af7eacdf0011010001fe0303024a252e7d475fd445607de39a265472aa74a9320ba2dac395faa687e9e0336aeb7e9a7397e511b5afd9dc84557c80ac0f3d4d7bfec5ae16f20d41c8c84a04552a33870b930420e230e179564f6d19bb153145e76c33ae993886c388832b0fa042ddda7f133924f3854481533e0ede31d51278c0519b29abc3bf53da673e13e3e1214b52413d179d7f66deee35cac8eacb060f78379d70ef4af8607e68131ff529439668fc39c9ce6dfef8a5ac234d234802cbfb749a26107db26406213ae5c06d4673253a3cbee1fcbae58d6ab77e38d6e2c0e7c6317c48e054edadb5a40d0d48acb44643d998139a8a66bb820be1f3f80185bc777d14b5954b60effe2448a036d565c6bc0b915fcea518acdd20ab07bc1529f561c58cd044f723109b93f6fd99f876ff891d64306b5d08f48bab59f38695e9109c4dec34013ba3153488ce070268381ba923ee1eb77125b36afcb4347ec3478c8f2735b06ef17351d872e577fa95d0c397c88c71b59629a36aec"
+
+// Generated by `gpg --export-secret-keys` followed by a manual extraction of
+// the ElGamal subkey from the packets.
+const privKeyElGamalHex = "9d0157044df9ee1a100400eb8e136a58ec39b582629cdadf830bc64e0a94ed8103ca8bb247b27b11b46d1d25297ef4bcc3071785ba0c0bedfe89eabc5287fcc0edf81ab5896c1c8e4b20d27d79813c7aede75320b33eaeeaa586edc00fd1036c10133e6ba0ff277245d0d59d04b2b3421b7244aca5f4a8d870c6f1c1fbff9e1c26699a860b9504f35ca1d700030503fd1ededd3b840795be6d9ccbe3c51ee42e2f39233c432b831ddd9c4e72b7025a819317e47bf94f9ee316d7273b05d5fcf2999c3a681f519b1234bbfa6d359b4752bd9c3f77d6b6456cde152464763414ca130f4e91d91041432f90620fec0e6d6b5116076c2985d5aeaae13be492b9b329efcaf7ee25120159a0a30cd976b42d7afe030302dae7eb80db744d4960c4df930d57e87fe81412eaace9f900e6c839817a614ddb75ba6603b9417c33ea7b6c93967dfa2bcff3fa3c74a5ce2c962db65b03aece14c96cbd0038fc"
diff --git a/libgo/go/crypto/openpgp/packet/public_key.go b/libgo/go/crypto/openpgp/packet/public_key.go
index cd4a9ae..e6b0ae5 100644
--- a/libgo/go/crypto/openpgp/packet/public_key.go
+++ b/libgo/go/crypto/openpgp/packet/public_key.go
@@ -7,6 +7,7 @@ package packet
import (
"big"
"crypto/dsa"
+ "crypto/openpgp/elgamal"
"crypto/openpgp/error"
"crypto/rsa"
"crypto/sha1"
@@ -30,6 +31,28 @@ type PublicKey struct {
n, e, p, q, g, y parsedMPI
}
+func fromBig(n *big.Int) parsedMPI {
+ return parsedMPI{
+ bytes: n.Bytes(),
+ bitLength: uint16(n.BitLen()),
+ }
+}
+
+// NewRSAPublicKey returns a PublicKey that wraps the given rsa.PublicKey.
+func NewRSAPublicKey(creationTimeSecs uint32, pub *rsa.PublicKey, isSubkey bool) *PublicKey {
+ pk := &PublicKey{
+ CreationTime: creationTimeSecs,
+ PubKeyAlgo: PubKeyAlgoRSA,
+ PublicKey: pub,
+ IsSubkey: isSubkey,
+ n: fromBig(pub.N),
+ e: fromBig(big.NewInt(int64(pub.E))),
+ }
+
+ pk.setFingerPrintAndKeyId()
+ return pk
+}
+
func (pk *PublicKey) parse(r io.Reader) (err os.Error) {
// RFC 4880, section 5.5.2
var buf [6]byte
@@ -47,6 +70,8 @@ func (pk *PublicKey) parse(r io.Reader) (err os.Error) {
err = pk.parseRSA(r)
case PubKeyAlgoDSA:
err = pk.parseDSA(r)
+ case PubKeyAlgoElGamal:
+ err = pk.parseElGamal(r)
default:
err = error.UnsupportedError("public key type: " + strconv.Itoa(int(pk.PubKeyAlgo)))
}
@@ -54,14 +79,17 @@ func (pk *PublicKey) parse(r io.Reader) (err os.Error) {
return
}
+ pk.setFingerPrintAndKeyId()
+ return
+}
+
+func (pk *PublicKey) setFingerPrintAndKeyId() {
// RFC 4880, section 12.2
fingerPrint := sha1.New()
pk.SerializeSignaturePrefix(fingerPrint)
- pk.Serialize(fingerPrint)
+ pk.serializeWithoutHeaders(fingerPrint)
copy(pk.Fingerprint[:], fingerPrint.Sum())
pk.KeyId = binary.BigEndian.Uint64(pk.Fingerprint[12:20])
-
- return
}
// parseRSA parses RSA public key material from the given Reader. See RFC 4880,
@@ -92,7 +120,7 @@ func (pk *PublicKey) parseRSA(r io.Reader) (err os.Error) {
return
}
-// parseRSA parses DSA public key material from the given Reader. See RFC 4880,
+// parseDSA parses DSA public key material from the given Reader. See RFC 4880,
// section 5.5.2.
func (pk *PublicKey) parseDSA(r io.Reader) (err os.Error) {
pk.p.bytes, pk.p.bitLength, err = readMPI(r)
@@ -121,6 +149,30 @@ func (pk *PublicKey) parseDSA(r io.Reader) (err os.Error) {
return
}
+// parseElGamal parses ElGamal public key material from the given Reader. See
+// RFC 4880, section 5.5.2.
+func (pk *PublicKey) parseElGamal(r io.Reader) (err os.Error) {
+ pk.p.bytes, pk.p.bitLength, err = readMPI(r)
+ if err != nil {
+ return
+ }
+ pk.g.bytes, pk.g.bitLength, err = readMPI(r)
+ if err != nil {
+ return
+ }
+ pk.y.bytes, pk.y.bitLength, err = readMPI(r)
+ if err != nil {
+ return
+ }
+
+ elgamal := new(elgamal.PublicKey)
+ elgamal.P = new(big.Int).SetBytes(pk.p.bytes)
+ elgamal.G = new(big.Int).SetBytes(pk.g.bytes)
+ elgamal.Y = new(big.Int).SetBytes(pk.y.bytes)
+ pk.PublicKey = elgamal
+ return
+}
+
// SerializeSignaturePrefix writes the prefix for this public key to the given Writer.
// The prefix is used when calculating a signature over this public key. See
// RFC 4880, section 5.2.4.
@@ -135,6 +187,10 @@ func (pk *PublicKey) SerializeSignaturePrefix(h hash.Hash) {
pLength += 2 + uint16(len(pk.q.bytes))
pLength += 2 + uint16(len(pk.g.bytes))
pLength += 2 + uint16(len(pk.y.bytes))
+ case PubKeyAlgoElGamal:
+ pLength += 2 + uint16(len(pk.p.bytes))
+ pLength += 2 + uint16(len(pk.g.bytes))
+ pLength += 2 + uint16(len(pk.y.bytes))
default:
panic("unknown public key algorithm")
}
@@ -143,9 +199,40 @@ func (pk *PublicKey) SerializeSignaturePrefix(h hash.Hash) {
return
}
-// Serialize marshals the PublicKey to w in the form of an OpenPGP public key
-// packet, not including the packet header.
func (pk *PublicKey) Serialize(w io.Writer) (err os.Error) {
+ length := 6 // 6 byte header
+
+ switch pk.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
+ length += 2 + len(pk.n.bytes)
+ length += 2 + len(pk.e.bytes)
+ case PubKeyAlgoDSA:
+ length += 2 + len(pk.p.bytes)
+ length += 2 + len(pk.q.bytes)
+ length += 2 + len(pk.g.bytes)
+ length += 2 + len(pk.y.bytes)
+ case PubKeyAlgoElGamal:
+ length += 2 + len(pk.p.bytes)
+ length += 2 + len(pk.g.bytes)
+ length += 2 + len(pk.y.bytes)
+ default:
+ panic("unknown public key algorithm")
+ }
+
+ packetType := packetTypePublicKey
+ if pk.IsSubkey {
+ packetType = packetTypePublicSubkey
+ }
+ err = serializeHeader(w, packetType, length)
+ if err != nil {
+ return
+ }
+ return pk.serializeWithoutHeaders(w)
+}
+
+// serializeWithoutHeaders marshals the PublicKey to w in the form of an
+// OpenPGP public key packet, not including the packet header.
+func (pk *PublicKey) serializeWithoutHeaders(w io.Writer) (err os.Error) {
var buf [6]byte
buf[0] = 4
buf[1] = byte(pk.CreationTime >> 24)
@@ -164,13 +251,15 @@ func (pk *PublicKey) Serialize(w io.Writer) (err os.Error) {
return writeMPIs(w, pk.n, pk.e)
case PubKeyAlgoDSA:
return writeMPIs(w, pk.p, pk.q, pk.g, pk.y)
+ case PubKeyAlgoElGamal:
+ return writeMPIs(w, pk.p, pk.g, pk.y)
}
return error.InvalidArgumentError("bad public-key algorithm")
}
// CanSign returns true iff this public key can generate signatures
func (pk *PublicKey) CanSign() bool {
- return pk.PubKeyAlgo != PubKeyAlgoRSAEncryptOnly && pk.PubKeyAlgo != PubKeyAlgoElgamal
+ return pk.PubKeyAlgo != PubKeyAlgoRSAEncryptOnly && pk.PubKeyAlgo != PubKeyAlgoElGamal
}
// VerifySignature returns nil iff sig is a valid signature, made by this
@@ -194,14 +283,14 @@ func (pk *PublicKey) VerifySignature(signed hash.Hash, sig *Signature) (err os.E
switch pk.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
rsaPublicKey, _ := pk.PublicKey.(*rsa.PublicKey)
- err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, sig.RSASignature)
+ err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, sig.RSASignature.bytes)
if err != nil {
return error.SignatureError("RSA verification failure")
}
return nil
case PubKeyAlgoDSA:
dsaPublicKey, _ := pk.PublicKey.(*dsa.PublicKey)
- if !dsa.Verify(dsaPublicKey, hashBytes, sig.DSASigR, sig.DSASigS) {
+ if !dsa.Verify(dsaPublicKey, hashBytes, new(big.Int).SetBytes(sig.DSASigR.bytes), new(big.Int).SetBytes(sig.DSASigS.bytes)) {
return error.SignatureError("DSA verification failure")
}
return nil
@@ -211,34 +300,43 @@ func (pk *PublicKey) VerifySignature(signed hash.Hash, sig *Signature) (err os.E
panic("unreachable")
}
-// VerifyKeySignature returns nil iff sig is a valid signature, make by this
-// public key, of the public key in signed.
-func (pk *PublicKey) VerifyKeySignature(signed *PublicKey, sig *Signature) (err os.Error) {
- h := sig.Hash.New()
+// keySignatureHash returns a Hash of the message that needs to be signed for
+// pk to assert a subkey relationship to signed.
+func keySignatureHash(pk, signed *PublicKey, sig *Signature) (h hash.Hash, err os.Error) {
+ h = sig.Hash.New()
if h == nil {
- return error.UnsupportedError("hash function")
+ return nil, error.UnsupportedError("hash function")
}
// RFC 4880, section 5.2.4
pk.SerializeSignaturePrefix(h)
- pk.Serialize(h)
+ pk.serializeWithoutHeaders(h)
signed.SerializeSignaturePrefix(h)
- signed.Serialize(h)
+ signed.serializeWithoutHeaders(h)
+ return
+}
+// VerifyKeySignature returns nil iff sig is a valid signature, made by this
+// public key, of signed.
+func (pk *PublicKey) VerifyKeySignature(signed *PublicKey, sig *Signature) (err os.Error) {
+ h, err := keySignatureHash(pk, signed, sig)
+ if err != nil {
+ return err
+ }
return pk.VerifySignature(h, sig)
}
-// VerifyUserIdSignature returns nil iff sig is a valid signature, make by this
-// public key, of the given user id.
-func (pk *PublicKey) VerifyUserIdSignature(id string, sig *Signature) (err os.Error) {
- h := sig.Hash.New()
+// userIdSignatureHash returns a Hash of the message that needs to be signed
+// to assert that pk is a valid key for id.
+func userIdSignatureHash(id string, pk *PublicKey, sig *Signature) (h hash.Hash, err os.Error) {
+ h = sig.Hash.New()
if h == nil {
- return error.UnsupportedError("hash function")
+ return nil, error.UnsupportedError("hash function")
}
// RFC 4880, section 5.2.4
pk.SerializeSignaturePrefix(h)
- pk.Serialize(h)
+ pk.serializeWithoutHeaders(h)
var buf [5]byte
buf[0] = 0xb4
@@ -249,6 +347,16 @@ func (pk *PublicKey) VerifyUserIdSignature(id string, sig *Signature) (err os.Er
h.Write(buf[:])
h.Write([]byte(id))
+ return
+}
+
+// VerifyUserIdSignature returns nil iff sig is a valid signature, made by this
+// public key, of id.
+func (pk *PublicKey) VerifyUserIdSignature(id string, sig *Signature) (err os.Error) {
+ h, err := userIdSignatureHash(id, pk, sig)
+ if err != nil {
+ return err
+ }
return pk.VerifySignature(h, sig)
}
@@ -272,7 +380,7 @@ type parsedMPI struct {
bitLength uint16
}
-// writeMPIs is a utility function for serialising several big integers to the
+// writeMPIs is a utility function for serializing several big integers to the
// given Writer.
func writeMPIs(w io.Writer, mpis ...parsedMPI) (err os.Error) {
for _, mpi := range mpis {
diff --git a/libgo/go/crypto/openpgp/packet/public_key_test.go b/libgo/go/crypto/openpgp/packet/public_key_test.go
index 069388c..6e8bfbc 100644
--- a/libgo/go/crypto/openpgp/packet/public_key_test.go
+++ b/libgo/go/crypto/openpgp/packet/public_key_test.go
@@ -28,12 +28,12 @@ func TestPublicKeyRead(t *testing.T) {
packet, err := Read(readerFromHex(test.hexData))
if err != nil {
t.Errorf("#%d: Read error: %s", i, err)
- return
+ continue
}
pk, ok := packet.(*PublicKey)
if !ok {
t.Errorf("#%d: failed to parse, got: %#v", i, packet)
- return
+ continue
}
if pk.PubKeyAlgo != test.pubKeyAlgo {
t.Errorf("#%d: bad public key algorithm got:%x want:%x", i, pk.PubKeyAlgo, test.pubKeyAlgo)
@@ -57,6 +57,38 @@ func TestPublicKeyRead(t *testing.T) {
}
}
+func TestPublicKeySerialize(t *testing.T) {
+ for i, test := range pubKeyTests {
+ packet, err := Read(readerFromHex(test.hexData))
+ if err != nil {
+ t.Errorf("#%d: Read error: %s", i, err)
+ continue
+ }
+ pk, ok := packet.(*PublicKey)
+ if !ok {
+ t.Errorf("#%d: failed to parse, got: %#v", i, packet)
+ continue
+ }
+ serializeBuf := bytes.NewBuffer(nil)
+ err = pk.Serialize(serializeBuf)
+ if err != nil {
+ t.Errorf("#%d: failed to serialize: %s", i, err)
+ continue
+ }
+
+ packet, err = Read(serializeBuf)
+ if err != nil {
+ t.Errorf("#%d: Read error (from serialized data): %s", i, err)
+ continue
+ }
+ pk, ok = packet.(*PublicKey)
+ if !ok {
+ t.Errorf("#%d: failed to parse serialized data, got: %#v", i, packet)
+ continue
+ }
+ }
+}
+
const rsaFingerprintHex = "5fb74b1d03b1e3cb31bc2f8aa34d7e18c20c31bb"
const rsaPkDataHex = "988d044d3c5c10010400b1d13382944bd5aba23a4312968b5095d14f947f600eb478e14a6fcb16b0e0cac764884909c020bc495cfcc39a935387c661507bdb236a0612fb582cac3af9b29cc2c8c70090616c41b662f4da4c1201e195472eb7f4ae1ccbcbf9940fe21d985e379a5563dde5b9a23d35f1cfaa5790da3b79db26f23695107bfaca8e7b5bcd0011010001"
diff --git a/libgo/go/crypto/openpgp/packet/signature.go b/libgo/go/crypto/openpgp/packet/signature.go
index 719657e..7577e28 100644
--- a/libgo/go/crypto/openpgp/packet/signature.go
+++ b/libgo/go/crypto/openpgp/packet/signature.go
@@ -5,7 +5,6 @@
package packet
import (
- "big"
"crypto"
"crypto/dsa"
"crypto/openpgp/error"
@@ -32,8 +31,11 @@ type Signature struct {
HashTag [2]byte
CreationTime uint32 // Unix epoch time
- RSASignature []byte
- DSASigR, DSASigS *big.Int
+ RSASignature parsedMPI
+ DSASigR, DSASigS parsedMPI
+
+ // rawSubpackets contains the unparsed subpackets, in order.
+ rawSubpackets []outputSubpacket
// The following are optional so are nil when not included in the
// signature.
@@ -128,14 +130,11 @@ func (sig *Signature) parse(r io.Reader) (err os.Error) {
switch sig.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
- sig.RSASignature, _, err = readMPI(r)
+ sig.RSASignature.bytes, sig.RSASignature.bitLength, err = readMPI(r)
case PubKeyAlgoDSA:
- var rBytes, sBytes []byte
- rBytes, _, err = readMPI(r)
- sig.DSASigR = new(big.Int).SetBytes(rBytes)
+ sig.DSASigR.bytes, sig.DSASigR.bitLength, err = readMPI(r)
if err == nil {
- sBytes, _, err = readMPI(r)
- sig.DSASigS = new(big.Int).SetBytes(sBytes)
+ sig.DSASigS.bytes, sig.DSASigS.bitLength, err = readMPI(r)
}
default:
panic("unreachable")
@@ -177,7 +176,11 @@ const (
// parseSignatureSubpacket parses a single subpacket. len(subpacket) is >= 1.
func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (rest []byte, err os.Error) {
// RFC 4880, section 5.2.3.1
- var length uint32
+ var (
+ length uint32
+ packetType signatureSubpacketType
+ isCritical bool
+ )
switch {
case subpacket[0] < 192:
length = uint32(subpacket[0])
@@ -207,10 +210,11 @@ func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (r
err = error.StructuralError("zero length signature subpacket")
return
}
- packetType := subpacket[0] & 0x7f
- isCritial := subpacket[0]&0x80 == 0x80
+ packetType = signatureSubpacketType(subpacket[0] & 0x7f)
+ isCritical = subpacket[0]&0x80 == 0x80
subpacket = subpacket[1:]
- switch signatureSubpacketType(packetType) {
+ sig.rawSubpackets = append(sig.rawSubpackets, outputSubpacket{isHashed, packetType, isCritical, subpacket})
+ switch packetType {
case creationTimeSubpacket:
if !isHashed {
err = error.StructuralError("signature creation time in non-hashed area")
@@ -309,7 +313,7 @@ func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (r
}
default:
- if isCritial {
+ if isCritical {
err = error.UnsupportedError("unknown critical signature subpacket type " + strconv.Itoa(int(packetType)))
return
}
@@ -381,7 +385,6 @@ func serializeSubpackets(to []byte, subpackets []outputSubpacket, hashed bool) {
// buildHashSuffix constructs the HashSuffix member of sig in preparation for signing.
func (sig *Signature) buildHashSuffix() (err os.Error) {
- sig.outSubpackets = sig.buildSubpackets()
hashedSubpacketsLen := subpacketsLength(sig.outSubpackets, true)
var ok bool
@@ -393,7 +396,7 @@ func (sig *Signature) buildHashSuffix() (err os.Error) {
sig.HashSuffix[3], ok = s2k.HashToHashId(sig.Hash)
if !ok {
sig.HashSuffix = nil
- return error.InvalidArgumentError("hash cannot be repesented in OpenPGP: " + strconv.Itoa(int(sig.Hash)))
+ return error.InvalidArgumentError("hash cannot be represented in OpenPGP: " + strconv.Itoa(int(sig.Hash)))
}
sig.HashSuffix[4] = byte(hashedSubpacketsLen >> 8)
sig.HashSuffix[5] = byte(hashedSubpacketsLen)
@@ -420,45 +423,72 @@ func (sig *Signature) signPrepareHash(h hash.Hash) (digest []byte, err os.Error)
return
}
-// SignRSA signs a message with an RSA private key. The hash, h, must contain
+// Sign signs a message with a private key. The hash, h, must contain
// the hash of the message to be signed and will be mutated by this function.
// On success, the signature is stored in sig. Call Serialize to write it out.
-func (sig *Signature) SignRSA(h hash.Hash, priv *rsa.PrivateKey) (err os.Error) {
+func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey) (err os.Error) {
+ sig.outSubpackets = sig.buildSubpackets()
digest, err := sig.signPrepareHash(h)
if err != nil {
return
}
- sig.RSASignature, err = rsa.SignPKCS1v15(rand.Reader, priv, sig.Hash, digest)
+
+ switch priv.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
+ sig.RSASignature.bytes, err = rsa.SignPKCS1v15(rand.Reader, priv.PrivateKey.(*rsa.PrivateKey), sig.Hash, digest)
+ sig.RSASignature.bitLength = uint16(8 * len(sig.RSASignature.bytes))
+ case PubKeyAlgoDSA:
+ r, s, err := dsa.Sign(rand.Reader, priv.PrivateKey.(*dsa.PrivateKey), digest)
+ if err == nil {
+ sig.DSASigR.bytes = r.Bytes()
+ sig.DSASigR.bitLength = uint16(8 * len(sig.DSASigR.bytes))
+ sig.DSASigS.bytes = s.Bytes()
+ sig.DSASigS.bitLength = uint16(8 * len(sig.DSASigS.bytes))
+ }
+ default:
+ err = error.UnsupportedError("public key algorithm: " + strconv.Itoa(int(sig.PubKeyAlgo)))
+ }
+
return
}
-// SignDSA signs a message with a DSA private key. The hash, h, must contain
-// the hash of the message to be signed and will be mutated by this function.
-// On success, the signature is stored in sig. Call Serialize to write it out.
-func (sig *Signature) SignDSA(h hash.Hash, priv *dsa.PrivateKey) (err os.Error) {
- digest, err := sig.signPrepareHash(h)
+// SignUserId computes a signature from priv, asserting that pub is a valid
+// key for the identity id. On success, the signature is stored in sig. Call
+// Serialize to write it out.
+func (sig *Signature) SignUserId(id string, pub *PublicKey, priv *PrivateKey) os.Error {
+ h, err := userIdSignatureHash(id, pub, sig)
if err != nil {
- return
+ return nil
}
- sig.DSASigR, sig.DSASigS, err = dsa.Sign(rand.Reader, priv, digest)
- return
+ return sig.Sign(h, priv)
+}
+
+// SignKey computes a signature from priv, asserting that pub is a subkey. On
+// success, the signature is stored in sig. Call Serialize to write it out.
+func (sig *Signature) SignKey(pub *PublicKey, priv *PrivateKey) os.Error {
+ h, err := keySignatureHash(&priv.PublicKey, pub, sig)
+ if err != nil {
+ return err
+ }
+ return sig.Sign(h, priv)
}
// Serialize marshals sig to w. SignRSA or SignDSA must have been called first.
func (sig *Signature) Serialize(w io.Writer) (err os.Error) {
- if sig.RSASignature == nil && sig.DSASigR == nil {
+ if len(sig.outSubpackets) == 0 {
+ sig.outSubpackets = sig.rawSubpackets
+ }
+ if sig.RSASignature.bytes == nil && sig.DSASigR.bytes == nil {
return error.InvalidArgumentError("Signature: need to call SignRSA or SignDSA before Serialize")
}
sigLength := 0
switch sig.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
- sigLength = len(sig.RSASignature)
+ sigLength = 2 + len(sig.RSASignature.bytes)
case PubKeyAlgoDSA:
- sigLength = 2 /* MPI length */
- sigLength += (sig.DSASigR.BitLen() + 7) / 8
- sigLength += 2 /* MPI length */
- sigLength += (sig.DSASigS.BitLen() + 7) / 8
+ sigLength = 2 + len(sig.DSASigR.bytes)
+ sigLength += 2 + len(sig.DSASigS.bytes)
default:
panic("impossible")
}
@@ -466,7 +496,7 @@ func (sig *Signature) Serialize(w io.Writer) (err os.Error) {
unhashedSubpacketsLen := subpacketsLength(sig.outSubpackets, false)
length := len(sig.HashSuffix) - 6 /* trailer not included */ +
2 /* length of unhashed subpackets */ + unhashedSubpacketsLen +
- 2 /* hash tag */ + 2 /* length of signature MPI */ + sigLength
+ 2 /* hash tag */ + sigLength
err = serializeHeader(w, packetTypeSignature, length)
if err != nil {
return
@@ -493,12 +523,9 @@ func (sig *Signature) Serialize(w io.Writer) (err os.Error) {
switch sig.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
- err = writeMPI(w, 8*uint16(len(sig.RSASignature)), sig.RSASignature)
+ err = writeMPIs(w, sig.RSASignature)
case PubKeyAlgoDSA:
- err = writeBig(w, sig.DSASigR)
- if err == nil {
- err = writeBig(w, sig.DSASigS)
- }
+ err = writeMPIs(w, sig.DSASigR, sig.DSASigS)
default:
panic("impossible")
}
@@ -509,6 +536,7 @@ func (sig *Signature) Serialize(w io.Writer) (err os.Error) {
type outputSubpacket struct {
hashed bool // true if this subpacket is in the hashed area.
subpacketType signatureSubpacketType
+ isCritical bool
contents []byte
}
@@ -518,12 +546,12 @@ func (sig *Signature) buildSubpackets() (subpackets []outputSubpacket) {
creationTime[1] = byte(sig.CreationTime >> 16)
creationTime[2] = byte(sig.CreationTime >> 8)
creationTime[3] = byte(sig.CreationTime)
- subpackets = append(subpackets, outputSubpacket{true, creationTimeSubpacket, creationTime})
+ subpackets = append(subpackets, outputSubpacket{true, creationTimeSubpacket, false, creationTime})
if sig.IssuerKeyId != nil {
keyId := make([]byte, 8)
binary.BigEndian.PutUint64(keyId, *sig.IssuerKeyId)
- subpackets = append(subpackets, outputSubpacket{true, issuerSubpacket, keyId})
+ subpackets = append(subpackets, outputSubpacket{true, issuerSubpacket, false, keyId})
}
return
diff --git a/libgo/go/crypto/openpgp/packet/signature_test.go b/libgo/go/crypto/openpgp/packet/signature_test.go
index 1305548..c1bbde8 100644
--- a/libgo/go/crypto/openpgp/packet/signature_test.go
+++ b/libgo/go/crypto/openpgp/packet/signature_test.go
@@ -12,9 +12,7 @@ import (
)
func TestSignatureRead(t *testing.T) {
- signatureData, _ := hex.DecodeString(signatureDataHex)
- buf := bytes.NewBuffer(signatureData)
- packet, err := Read(buf)
+ packet, err := Read(readerFromHex(signatureDataHex))
if err != nil {
t.Error(err)
return
@@ -25,4 +23,20 @@ func TestSignatureRead(t *testing.T) {
}
}
-const signatureDataHex = "89011c04000102000605024cb45112000a0910ab105c91af38fb158f8d07ff5596ea368c5efe015bed6e78348c0f033c931d5f2ce5db54ce7f2a7e4b4ad64db758d65a7a71773edeab7ba2a9e0908e6a94a1175edd86c1d843279f045b021a6971a72702fcbd650efc393c5474d5b59a15f96d2eaad4c4c426797e0dcca2803ef41c6ff234d403eec38f31d610c344c06f2401c262f0993b2e66cad8a81ebc4322c723e0d4ba09fe917e8777658307ad8329adacba821420741009dfe87f007759f0982275d028a392c6ed983a0d846f890b36148c7358bdb8a516007fac760261ecd06076813831a36d0459075d1befa245ae7f7fb103d92ca759e9498fe60ef8078a39a3beda510deea251ea9f0a7f0df6ef42060f20780360686f3e400e"
+func TestSignatureReserialize(t *testing.T) {
+ packet, _ := Read(readerFromHex(signatureDataHex))
+ sig := packet.(*Signature)
+ out := new(bytes.Buffer)
+ err := sig.Serialize(out)
+ if err != nil {
+ t.Errorf("error reserializing: %s", err)
+ return
+ }
+
+ expected, _ := hex.DecodeString(signatureDataHex)
+ if !bytes.Equal(expected, out.Bytes()) {
+ t.Errorf("output doesn't match input (got vs expected):\n%s\n%s", hex.Dump(out.Bytes()), hex.Dump(expected))
+ }
+}
+
+const signatureDataHex = "c2c05c04000102000605024cb45112000a0910ab105c91af38fb158f8d07ff5596ea368c5efe015bed6e78348c0f033c931d5f2ce5db54ce7f2a7e4b4ad64db758d65a7a71773edeab7ba2a9e0908e6a94a1175edd86c1d843279f045b021a6971a72702fcbd650efc393c5474d5b59a15f96d2eaad4c4c426797e0dcca2803ef41c6ff234d403eec38f31d610c344c06f2401c262f0993b2e66cad8a81ebc4322c723e0d4ba09fe917e8777658307ad8329adacba821420741009dfe87f007759f0982275d028a392c6ed983a0d846f890b36148c7358bdb8a516007fac760261ecd06076813831a36d0459075d1befa245ae7f7fb103d92ca759e9498fe60ef8078a39a3beda510deea251ea9f0a7f0df6ef42060f20780360686f3e400e"
diff --git a/libgo/go/crypto/openpgp/packet/symmetric_key_encrypted.go b/libgo/go/crypto/openpgp/packet/symmetric_key_encrypted.go
index d9010f8..ad4f1d6 100644
--- a/libgo/go/crypto/openpgp/packet/symmetric_key_encrypted.go
+++ b/libgo/go/crypto/openpgp/packet/symmetric_key_encrypted.go
@@ -5,6 +5,7 @@
package packet
import (
+ "bytes"
"crypto/cipher"
"crypto/openpgp/error"
"crypto/openpgp/s2k"
@@ -27,6 +28,8 @@ type SymmetricKeyEncrypted struct {
encryptedKey []byte
}
+const symmetricKeyEncryptedVersion = 4
+
func (ske *SymmetricKeyEncrypted) parse(r io.Reader) (err os.Error) {
// RFC 4880, section 5.3.
var buf [2]byte
@@ -34,12 +37,12 @@ func (ske *SymmetricKeyEncrypted) parse(r io.Reader) (err os.Error) {
if err != nil {
return
}
- if buf[0] != 4 {
+ if buf[0] != symmetricKeyEncryptedVersion {
return error.UnsupportedError("SymmetricKeyEncrypted version")
}
ske.CipherFunc = CipherFunction(buf[1])
- if ske.CipherFunc.keySize() == 0 {
+ if ske.CipherFunc.KeySize() == 0 {
return error.UnsupportedError("unknown cipher: " + strconv.Itoa(int(buf[1])))
}
@@ -75,7 +78,7 @@ func (ske *SymmetricKeyEncrypted) Decrypt(passphrase []byte) os.Error {
return nil
}
- key := make([]byte, ske.CipherFunc.keySize())
+ key := make([]byte, ske.CipherFunc.KeySize())
ske.s2k(key, passphrase)
if len(ske.encryptedKey) == 0 {
@@ -100,3 +103,60 @@ func (ske *SymmetricKeyEncrypted) Decrypt(passphrase []byte) os.Error {
ske.Encrypted = false
return nil
}
+
+// SerializeSymmetricKeyEncrypted serializes a symmetric key packet to w. The
+// packet contains a random session key, encrypted by a key derived from the
+// given passphrase. The session key is returned and must be passed to
+// SerializeSymmetricallyEncrypted.
+func SerializeSymmetricKeyEncrypted(w io.Writer, rand io.Reader, passphrase []byte, cipherFunc CipherFunction) (key []byte, err os.Error) {
+ keySize := cipherFunc.KeySize()
+ if keySize == 0 {
+ return nil, error.UnsupportedError("unknown cipher: " + strconv.Itoa(int(cipherFunc)))
+ }
+
+ s2kBuf := new(bytes.Buffer)
+ keyEncryptingKey := make([]byte, keySize)
+ // s2k.Serialize salts and stretches the passphrase, and writes the
+ // resulting key to keyEncryptingKey and the s2k descriptor to s2kBuf.
+ err = s2k.Serialize(s2kBuf, keyEncryptingKey, rand, passphrase)
+ if err != nil {
+ return
+ }
+ s2kBytes := s2kBuf.Bytes()
+
+ packetLength := 2 /* header */ + len(s2kBytes) + 1 /* cipher type */ + keySize
+ err = serializeHeader(w, packetTypeSymmetricKeyEncrypted, packetLength)
+ if err != nil {
+ return
+ }
+
+ var buf [2]byte
+ buf[0] = symmetricKeyEncryptedVersion
+ buf[1] = byte(cipherFunc)
+ _, err = w.Write(buf[:])
+ if err != nil {
+ return
+ }
+ _, err = w.Write(s2kBytes)
+ if err != nil {
+ return
+ }
+
+ sessionKey := make([]byte, keySize)
+ _, err = io.ReadFull(rand, sessionKey)
+ if err != nil {
+ return
+ }
+ iv := make([]byte, cipherFunc.blockSize())
+ c := cipher.NewCFBEncrypter(cipherFunc.new(keyEncryptingKey), iv)
+ encryptedCipherAndKey := make([]byte, keySize+1)
+ c.XORKeyStream(encryptedCipherAndKey, buf[1:])
+ c.XORKeyStream(encryptedCipherAndKey[1:], sessionKey)
+ _, err = w.Write(encryptedCipherAndKey)
+ if err != nil {
+ return
+ }
+
+ key = sessionKey
+ return
+}
diff --git a/libgo/go/crypto/openpgp/packet/symmetric_key_encrypted_test.go b/libgo/go/crypto/openpgp/packet/symmetric_key_encrypted_test.go
index 717c8ff..823ec40 100644
--- a/libgo/go/crypto/openpgp/packet/symmetric_key_encrypted_test.go
+++ b/libgo/go/crypto/openpgp/packet/symmetric_key_encrypted_test.go
@@ -6,6 +6,7 @@ package packet
import (
"bytes"
+ "crypto/rand"
"encoding/hex"
"io/ioutil"
"os"
@@ -60,3 +61,41 @@ func TestSymmetricKeyEncrypted(t *testing.T) {
const symmetricallyEncryptedHex = "8c0d04030302371a0b38d884f02060c91cf97c9973b8e58e028e9501708ccfe618fb92afef7fa2d80ddadd93cf"
const symmetricallyEncryptedContentsHex = "cb1062004d14c4df636f6e74656e74732e0a"
+
+func TestSerializeSymmetricKeyEncrypted(t *testing.T) {
+ buf := bytes.NewBuffer(nil)
+ passphrase := []byte("testing")
+ cipherFunc := CipherAES128
+
+ key, err := SerializeSymmetricKeyEncrypted(buf, rand.Reader, passphrase, cipherFunc)
+ if err != nil {
+ t.Errorf("failed to serialize: %s", err)
+ return
+ }
+
+ p, err := Read(buf)
+ if err != nil {
+ t.Errorf("failed to reparse: %s", err)
+ return
+ }
+ ske, ok := p.(*SymmetricKeyEncrypted)
+ if !ok {
+ t.Errorf("parsed a different packet type: %#v", p)
+ return
+ }
+
+ if !ske.Encrypted {
+ t.Errorf("SKE not encrypted but should be")
+ }
+ if ske.CipherFunc != cipherFunc {
+ t.Errorf("SKE cipher function is %d (expected %d)", ske.CipherFunc, cipherFunc)
+ }
+ err = ske.Decrypt(passphrase)
+ if err != nil {
+ t.Errorf("failed to decrypt reparsed SKE: %s", err)
+ return
+ }
+ if !bytes.Equal(key, ske.Key) {
+ t.Errorf("keys don't match after Decrpyt: %x (original) vs %x (parsed)", key, ske.Key)
+ }
+}
diff --git a/libgo/go/crypto/openpgp/packet/symmetrically_encrypted.go b/libgo/go/crypto/openpgp/packet/symmetrically_encrypted.go
index fc19ffe..e33c9f3 100644
--- a/libgo/go/crypto/openpgp/packet/symmetrically_encrypted.go
+++ b/libgo/go/crypto/openpgp/packet/symmetrically_encrypted.go
@@ -7,6 +7,7 @@ package packet
import (
"crypto/cipher"
"crypto/openpgp/error"
+ "crypto/rand"
"crypto/sha1"
"crypto/subtle"
"hash"
@@ -24,6 +25,8 @@ type SymmetricallyEncrypted struct {
prefix []byte
}
+const symmetricallyEncryptedVersion = 1
+
func (se *SymmetricallyEncrypted) parse(r io.Reader) os.Error {
if se.MDC {
// See RFC 4880, section 5.13.
@@ -32,7 +35,7 @@ func (se *SymmetricallyEncrypted) parse(r io.Reader) os.Error {
if err != nil {
return err
}
- if buf[0] != 1 {
+ if buf[0] != symmetricallyEncryptedVersion {
return error.UnsupportedError("unknown SymmetricallyEncrypted version")
}
}
@@ -44,7 +47,7 @@ func (se *SymmetricallyEncrypted) parse(r io.Reader) os.Error {
// packet can be read. An incorrect key can, with high probability, be detected
// immediately and this will result in a KeyIncorrect error being returned.
func (se *SymmetricallyEncrypted) Decrypt(c CipherFunction, key []byte) (io.ReadCloser, os.Error) {
- keySize := c.keySize()
+ keySize := c.KeySize()
if keySize == 0 {
return nil, error.UnsupportedError("unknown cipher: " + strconv.Itoa(int(c)))
}
@@ -174,6 +177,9 @@ func (ser *seMDCReader) Read(buf []byte) (n int, err os.Error) {
return
}
+// This is a new-format packet tag byte for a type 19 (MDC) packet.
+const mdcPacketTagByte = byte(0x80) | 0x40 | 19
+
func (ser *seMDCReader) Close() os.Error {
if ser.error {
return error.SignatureError("error during reading")
@@ -191,16 +197,95 @@ func (ser *seMDCReader) Close() os.Error {
}
}
- // This is a new-format packet tag byte for a type 19 (MDC) packet.
- const mdcPacketTagByte = byte(0x80) | 0x40 | 19
if ser.trailer[0] != mdcPacketTagByte || ser.trailer[1] != sha1.Size {
return error.SignatureError("MDC packet not found")
}
ser.h.Write(ser.trailer[:2])
final := ser.h.Sum()
- if subtle.ConstantTimeCompare(final, ser.trailer[2:]) == 1 {
+ if subtle.ConstantTimeCompare(final, ser.trailer[2:]) != 1 {
return error.SignatureError("hash mismatch")
}
return nil
}
+
+// An seMDCWriter writes through to an io.WriteCloser while maintains a running
+// hash of the data written. On close, it emits an MDC packet containing the
+// running hash.
+type seMDCWriter struct {
+ w io.WriteCloser
+ h hash.Hash
+}
+
+func (w *seMDCWriter) Write(buf []byte) (n int, err os.Error) {
+ w.h.Write(buf)
+ return w.w.Write(buf)
+}
+
+func (w *seMDCWriter) Close() (err os.Error) {
+ var buf [mdcTrailerSize]byte
+
+ buf[0] = mdcPacketTagByte
+ buf[1] = sha1.Size
+ w.h.Write(buf[:2])
+ digest := w.h.Sum()
+ copy(buf[2:], digest)
+
+ _, err = w.w.Write(buf[:])
+ if err != nil {
+ return
+ }
+ return w.w.Close()
+}
+
+// noOpCloser is like an ioutil.NopCloser, but for an io.Writer.
+type noOpCloser struct {
+ w io.Writer
+}
+
+func (c noOpCloser) Write(data []byte) (n int, err os.Error) {
+ return c.w.Write(data)
+}
+
+func (c noOpCloser) Close() os.Error {
+ return nil
+}
+
+// SerializeSymmetricallyEncrypted serializes a symmetrically encrypted packet
+// to w and returns a WriteCloser to which the to-be-encrypted packets can be
+// written.
+func SerializeSymmetricallyEncrypted(w io.Writer, c CipherFunction, key []byte) (contents io.WriteCloser, err os.Error) {
+ if c.KeySize() != len(key) {
+ return nil, error.InvalidArgumentError("SymmetricallyEncrypted.Serialize: bad key length")
+ }
+ writeCloser := noOpCloser{w}
+ ciphertext, err := serializeStreamHeader(writeCloser, packetTypeSymmetricallyEncryptedMDC)
+ if err != nil {
+ return
+ }
+
+ _, err = ciphertext.Write([]byte{symmetricallyEncryptedVersion})
+ if err != nil {
+ return
+ }
+
+ block := c.new(key)
+ blockSize := block.BlockSize()
+ iv := make([]byte, blockSize)
+ _, err = rand.Reader.Read(iv)
+ if err != nil {
+ return
+ }
+ s, prefix := cipher.NewOCFBEncrypter(block, iv, cipher.OCFBNoResync)
+ _, err = ciphertext.Write(prefix)
+ if err != nil {
+ return
+ }
+ plaintext := cipher.StreamWriter{S: s, W: ciphertext}
+
+ h := sha1.New()
+ h.Write(iv)
+ h.Write(iv[blockSize-2:])
+ contents = &seMDCWriter{w: plaintext, h: h}
+ return
+}
diff --git a/libgo/go/crypto/openpgp/packet/symmetrically_encrypted_test.go b/libgo/go/crypto/openpgp/packet/symmetrically_encrypted_test.go
index 5543b20..1054fc2 100644
--- a/libgo/go/crypto/openpgp/packet/symmetrically_encrypted_test.go
+++ b/libgo/go/crypto/openpgp/packet/symmetrically_encrypted_test.go
@@ -9,6 +9,7 @@ import (
"crypto/openpgp/error"
"crypto/sha1"
"encoding/hex"
+ "io"
"io/ioutil"
"os"
"testing"
@@ -76,3 +77,48 @@ func testMDCReader(t *testing.T) {
}
const mdcPlaintextHex = "a302789c3b2d93c4e0eb9aba22283539b3203335af44a134afb800c849cb4c4de10200aff40b45d31432c80cb384299a0655966d6939dfdeed1dddf980"
+
+func TestSerialize(t *testing.T) {
+ buf := bytes.NewBuffer(nil)
+ c := CipherAES128
+ key := make([]byte, c.KeySize())
+
+ w, err := SerializeSymmetricallyEncrypted(buf, c, key)
+ if err != nil {
+ t.Errorf("error from SerializeSymmetricallyEncrypted: %s", err)
+ return
+ }
+
+ contents := []byte("hello world\n")
+
+ w.Write(contents)
+ w.Close()
+
+ p, err := Read(buf)
+ if err != nil {
+ t.Errorf("error from Read: %s", err)
+ return
+ }
+
+ se, ok := p.(*SymmetricallyEncrypted)
+ if !ok {
+ t.Errorf("didn't read a *SymmetricallyEncrypted")
+ return
+ }
+
+ r, err := se.Decrypt(c, key)
+ if err != nil {
+ t.Errorf("error from Decrypt: %s", err)
+ return
+ }
+
+ contentsCopy := bytes.NewBuffer(nil)
+ _, err = io.Copy(contentsCopy, r)
+ if err != nil {
+ t.Errorf("error from io.Copy: %s", err)
+ return
+ }
+ if !bytes.Equal(contentsCopy.Bytes(), contents) {
+ t.Errorf("contents not equal got: %x want: %x", contentsCopy.Bytes(), contents)
+ }
+}
diff --git a/libgo/go/crypto/openpgp/packet/userid.go b/libgo/go/crypto/openpgp/packet/userid.go
index ed2ad77..0580ba3 100644
--- a/libgo/go/crypto/openpgp/packet/userid.go
+++ b/libgo/go/crypto/openpgp/packet/userid.go
@@ -20,6 +20,51 @@ type UserId struct {
Name, Comment, Email string
}
+func hasInvalidCharacters(s string) bool {
+ for _, c := range s {
+ switch c {
+ case '(', ')', '<', '>', 0:
+ return true
+ }
+ }
+ return false
+}
+
+// NewUserId returns a UserId or nil if any of the arguments contain invalid
+// characters. The invalid characters are '\x00', '(', ')', '<' and '>'
+func NewUserId(name, comment, email string) *UserId {
+ // RFC 4880 doesn't deal with the structure of userid strings; the
+ // name, comment and email form is just a convention. However, there's
+ // no convention about escaping the metacharacters and GPG just refuses
+ // to create user ids where, say, the name contains a '('. We mirror
+ // this behaviour.
+
+ if hasInvalidCharacters(name) || hasInvalidCharacters(comment) || hasInvalidCharacters(email) {
+ return nil
+ }
+
+ uid := new(UserId)
+ uid.Name, uid.Comment, uid.Email = name, comment, email
+ uid.Id = name
+ if len(comment) > 0 {
+ if len(uid.Id) > 0 {
+ uid.Id += " "
+ }
+ uid.Id += "("
+ uid.Id += comment
+ uid.Id += ")"
+ }
+ if len(email) > 0 {
+ if len(uid.Id) > 0 {
+ uid.Id += " "
+ }
+ uid.Id += "<"
+ uid.Id += email
+ uid.Id += ">"
+ }
+ return uid
+}
+
func (uid *UserId) parse(r io.Reader) (err os.Error) {
// RFC 4880, section 5.11
b, err := ioutil.ReadAll(r)
@@ -31,6 +76,17 @@ func (uid *UserId) parse(r io.Reader) (err os.Error) {
return
}
+// Serialize marshals uid to w in the form of an OpenPGP packet, including
+// header.
+func (uid *UserId) Serialize(w io.Writer) os.Error {
+ err := serializeHeader(w, packetTypeUserId, len(uid.Id))
+ if err != nil {
+ return err
+ }
+ _, err = w.Write([]byte(uid.Id))
+ return err
+}
+
// parseUserId extracts the name, comment and email from a user id string that
// is formatted as "Full Name (Comment) <email@example.com>".
func parseUserId(id string) (name, comment, email string) {
diff --git a/libgo/go/crypto/openpgp/packet/userid_test.go b/libgo/go/crypto/openpgp/packet/userid_test.go
index 394873d..2968193 100644
--- a/libgo/go/crypto/openpgp/packet/userid_test.go
+++ b/libgo/go/crypto/openpgp/packet/userid_test.go
@@ -40,3 +40,48 @@ func TestParseUserId(t *testing.T) {
}
}
}
+
+var newUserIdTests = []struct {
+ name, comment, email, id string
+}{
+ {"foo", "", "", "foo"},
+ {"", "bar", "", "(bar)"},
+ {"", "", "baz", "<baz>"},
+ {"foo", "bar", "", "foo (bar)"},
+ {"foo", "", "baz", "foo <baz>"},
+ {"", "bar", "baz", "(bar) <baz>"},
+ {"foo", "bar", "baz", "foo (bar) <baz>"},
+}
+
+func TestNewUserId(t *testing.T) {
+ for i, test := range newUserIdTests {
+ uid := NewUserId(test.name, test.comment, test.email)
+ if uid == nil {
+ t.Errorf("#%d: returned nil", i)
+ continue
+ }
+ if uid.Id != test.id {
+ t.Errorf("#%d: got '%s', want '%s'", i, uid.Id, test.id)
+ }
+ }
+}
+
+var invalidNewUserIdTests = []struct {
+ name, comment, email string
+}{
+ {"foo(", "", ""},
+ {"foo<", "", ""},
+ {"", "bar)", ""},
+ {"", "bar<", ""},
+ {"", "", "baz>"},
+ {"", "", "baz)"},
+ {"", "", "baz\x00"},
+}
+
+func TestNewUserIdWithInvalidInput(t *testing.T) {
+ for i, test := range invalidNewUserIdTests {
+ if uid := NewUserId(test.name, test.comment, test.email); uid != nil {
+ t.Errorf("#%d: returned non-nil value: %#v", i, uid)
+ }
+ }
+}
diff --git a/libgo/go/crypto/openpgp/read.go b/libgo/go/crypto/openpgp/read.go
index 4f84dff..d95f613 100644
--- a/libgo/go/crypto/openpgp/read.go
+++ b/libgo/go/crypto/openpgp/read.go
@@ -10,7 +10,6 @@ import (
"crypto/openpgp/armor"
"crypto/openpgp/error"
"crypto/openpgp/packet"
- "crypto/rsa"
_ "crypto/sha256"
"hash"
"io"
@@ -44,7 +43,7 @@ type MessageDetails struct {
DecryptedWith Key // the private key used to decrypt the message, if any.
IsSigned bool // true if the message is signed.
SignedByKeyId uint64 // the key id of the signer, if any.
- SignedBy *Key // the key of the signer, if availible.
+ SignedBy *Key // the key of the signer, if available.
LiteralData *packet.LiteralData // the metadata of the contents
UnverifiedBody io.Reader // the contents of the message.
@@ -57,7 +56,6 @@ type MessageDetails struct {
// been consumed. Once EOF has been seen, the following fields are
// valid. (An authentication code failure is reported as a
// SignatureError error when reading from UnverifiedBody.)
-
SignatureError os.Error // nil if the signature is good.
Signature *packet.Signature // the signature packet itself.
@@ -112,7 +110,10 @@ ParsePackets:
case *packet.EncryptedKey:
// This packet contains the decryption key encrypted to a public key.
md.EncryptedToKeyIds = append(md.EncryptedToKeyIds, p.KeyId)
- if p.Algo != packet.PubKeyAlgoRSA && p.Algo != packet.PubKeyAlgoRSAEncryptOnly {
+ switch p.Algo {
+ case packet.PubKeyAlgoRSA, packet.PubKeyAlgoRSAEncryptOnly, packet.PubKeyAlgoElGamal:
+ break
+ default:
continue
}
var keys []Key
@@ -145,7 +146,7 @@ ParsePackets:
// function so that it can decrypt a key or give us a passphrase.
FindKey:
for {
- // See if any of the keys already have a private key availible
+ // See if any of the keys already have a private key available
candidates = candidates[:0]
candidateFingerprints := make(map[string]bool)
@@ -155,7 +156,7 @@ FindKey:
}
if !pk.key.PrivateKey.Encrypted {
if len(pk.encryptedKey.Key) == 0 {
- pk.encryptedKey.DecryptRSA(pk.key.PrivateKey.PrivateKey.(*rsa.PrivateKey))
+ pk.encryptedKey.Decrypt(pk.key.PrivateKey)
}
if len(pk.encryptedKey.Key) == 0 {
continue
@@ -214,7 +215,7 @@ FindKey:
return readSignedMessage(packets, md, keyring)
}
-// readSignedMessage reads a possibily signed message if mdin is non-zero then
+// readSignedMessage reads a possibly signed message if mdin is non-zero then
// that structure is updated and returned. Otherwise a fresh MessageDetails is
// used.
func readSignedMessage(packets *packet.Reader, mdin *MessageDetails, keyring KeyRing) (md *MessageDetails, err os.Error) {
@@ -249,11 +250,12 @@ FindLiteralData:
md.IsSigned = true
md.SignedByKeyId = p.KeyId
keys := keyring.KeysById(p.KeyId)
- for _, key := range keys {
+ for i, key := range keys {
if key.SelfSignature.FlagsValid && !key.SelfSignature.FlagSign {
continue
}
- md.SignedBy = &key
+ md.SignedBy = &keys[i]
+ break
}
case *packet.LiteralData:
md.LiteralData = p
@@ -274,13 +276,13 @@ FindLiteralData:
// hashForSignature returns a pair of hashes that can be used to verify a
// signature. The signature may specify that the contents of the signed message
-// should be preprocessed (i.e. to normalise line endings). Thus this function
+// should be preprocessed (i.e. to normalize line endings). Thus this function
// returns two hashes. The second should be used to hash the message itself and
// performs any needed preprocessing.
func hashForSignature(hashId crypto.Hash, sigType packet.SignatureType) (hash.Hash, hash.Hash, os.Error) {
h := hashId.New()
if h == nil {
- return nil, nil, error.UnsupportedError("hash not availible: " + strconv.Itoa(int(hashId)))
+ return nil, nil, error.UnsupportedError("hash not available: " + strconv.Itoa(int(hashId)))
}
switch sigType {
diff --git a/libgo/go/crypto/openpgp/read_test.go b/libgo/go/crypto/openpgp/read_test.go
index 423c85b..4dc290e 100644
--- a/libgo/go/crypto/openpgp/read_test.go
+++ b/libgo/go/crypto/openpgp/read_test.go
@@ -33,6 +33,29 @@ func TestReadKeyRing(t *testing.T) {
}
}
+func TestRereadKeyRing(t *testing.T) {
+ kring, err := ReadKeyRing(readerFromHex(testKeys1And2Hex))
+ if err != nil {
+ t.Errorf("error in initial parse: %s", err)
+ return
+ }
+ out := new(bytes.Buffer)
+ err = kring[0].Serialize(out)
+ if err != nil {
+ t.Errorf("error in serialization: %s", err)
+ return
+ }
+ kring, err = ReadKeyRing(out)
+ if err != nil {
+ t.Errorf("error in second parse: %s", err)
+ return
+ }
+
+ if len(kring) != 1 || uint32(kring[0].PrimaryKey.KeyId) != 0xC20C31BB {
+ t.Errorf("bad keyring: %#v", kring)
+ }
+}
+
func TestReadPrivateKeyRing(t *testing.T) {
kring, err := ReadKeyRing(readerFromHex(testKeys1And2PrivateHex))
if err != nil {
@@ -102,49 +125,71 @@ func TestTextSignedMessage(t *testing.T) {
checkSignedMessage(t, signedTextMessageHex, signedTextInput)
}
-func TestSignedEncryptedMessage(t *testing.T) {
- expected := "Signed and encrypted message\n"
- kring, _ := ReadKeyRing(readerFromHex(testKeys1And2PrivateHex))
- prompt := func(keys []Key, symmetric bool) ([]byte, os.Error) {
- if symmetric {
- t.Errorf("prompt: message was marked as symmetrically encrypted")
- return nil, error.KeyIncorrectError
- }
+var signedEncryptedMessageTests = []struct {
+ keyRingHex string
+ messageHex string
+ signedByKeyId uint64
+ encryptedToKeyId uint64
+}{
+ {
+ testKeys1And2PrivateHex,
+ signedEncryptedMessageHex,
+ 0xa34d7e18c20c31bb,
+ 0x2a67d68660df41c7,
+ },
+ {
+ dsaElGamalTestKeysHex,
+ signedEncryptedMessage2Hex,
+ 0x33af447ccd759b09,
+ 0xcf6a7abcd43e3673,
+ },
+}
- if len(keys) == 0 {
- t.Error("prompt: no keys requested")
- return nil, error.KeyIncorrectError
+func TestSignedEncryptedMessage(t *testing.T) {
+ for i, test := range signedEncryptedMessageTests {
+ expected := "Signed and encrypted message\n"
+ kring, _ := ReadKeyRing(readerFromHex(test.keyRingHex))
+ prompt := func(keys []Key, symmetric bool) ([]byte, os.Error) {
+ if symmetric {
+ t.Errorf("prompt: message was marked as symmetrically encrypted")
+ return nil, error.KeyIncorrectError
+ }
+
+ if len(keys) == 0 {
+ t.Error("prompt: no keys requested")
+ return nil, error.KeyIncorrectError
+ }
+
+ err := keys[0].PrivateKey.Decrypt([]byte("passphrase"))
+ if err != nil {
+ t.Errorf("prompt: error decrypting key: %s", err)
+ return nil, error.KeyIncorrectError
+ }
+
+ return nil, nil
}
- err := keys[0].PrivateKey.Decrypt([]byte("passphrase"))
+ md, err := ReadMessage(readerFromHex(test.messageHex), kring, prompt)
if err != nil {
- t.Errorf("prompt: error decrypting key: %s", err)
- return nil, error.KeyIncorrectError
+ t.Errorf("#%d: error reading message: %s", i, err)
+ return
}
- return nil, nil
- }
-
- md, err := ReadMessage(readerFromHex(signedEncryptedMessageHex), kring, prompt)
- if err != nil {
- t.Errorf("error reading message: %s", err)
- return
- }
-
- if !md.IsSigned || md.SignedByKeyId != 0xa34d7e18c20c31bb || md.SignedBy == nil || !md.IsEncrypted || md.IsSymmetricallyEncrypted || len(md.EncryptedToKeyIds) == 0 || md.EncryptedToKeyIds[0] != 0x2a67d68660df41c7 {
- t.Errorf("bad MessageDetails: %#v", md)
- }
+ if !md.IsSigned || md.SignedByKeyId != test.signedByKeyId || md.SignedBy == nil || !md.IsEncrypted || md.IsSymmetricallyEncrypted || len(md.EncryptedToKeyIds) == 0 || md.EncryptedToKeyIds[0] != test.encryptedToKeyId {
+ t.Errorf("#%d: bad MessageDetails: %#v", i, md)
+ }
- contents, err := ioutil.ReadAll(md.UnverifiedBody)
- if err != nil {
- t.Errorf("error reading UnverifiedBody: %s", err)
- }
- if string(contents) != expected {
- t.Errorf("bad UnverifiedBody got:%s want:%s", string(contents), expected)
- }
+ contents, err := ioutil.ReadAll(md.UnverifiedBody)
+ if err != nil {
+ t.Errorf("#%d: error reading UnverifiedBody: %s", i, err)
+ }
+ if string(contents) != expected {
+ t.Errorf("#%d: bad UnverifiedBody got:%s want:%s", i, string(contents), expected)
+ }
- if md.SignatureError != nil || md.Signature == nil {
- t.Errorf("failed to validate: %s", md.SignatureError)
+ if md.SignatureError != nil || md.Signature == nil {
+ t.Errorf("#%d: failed to validate: %s", i, md.SignatureError)
+ }
}
}
@@ -193,9 +238,9 @@ func TestSymmetricallyEncrypted(t *testing.T) {
t.Errorf("ReadAll: %s", err)
}
- expectedCreatationTime := uint32(1295992998)
- if md.LiteralData.Time != expectedCreatationTime {
- t.Errorf("LiteralData.Time is %d, want %d", md.LiteralData.Time, expectedCreatationTime)
+ expectedCreationTime := uint32(1295992998)
+ if md.LiteralData.Time != expectedCreationTime {
+ t.Errorf("LiteralData.Time is %d, want %d", md.LiteralData.Time, expectedCreationTime)
}
if string(contents) != expected {
@@ -265,12 +310,16 @@ const testKeys1And2Hex = "988d044d3c5c10010400b1d13382944bd5aba23a4312968b5095d1
const testKeys1And2PrivateHex = "9501d8044d3c5c10010400b1d13382944bd5aba23a4312968b5095d14f947f600eb478e14a6fcb16b0e0cac764884909c020bc495cfcc39a935387c661507bdb236a0612fb582cac3af9b29cc2c8c70090616c41b662f4da4c1201e195472eb7f4ae1ccbcbf9940fe21d985e379a5563dde5b9a23d35f1cfaa5790da3b79db26f23695107bfaca8e7b5bcd00110100010003ff4d91393b9a8e3430b14d6209df42f98dc927425b881f1209f319220841273a802a97c7bdb8b3a7740b3ab5866c4d1d308ad0d3a79bd1e883aacf1ac92dfe720285d10d08752a7efe3c609b1d00f17f2805b217be53999a7da7e493bfc3e9618fd17018991b8128aea70a05dbce30e4fbe626aa45775fa255dd9177aabf4df7cf0200c1ded12566e4bc2bb590455e5becfb2e2c9796482270a943343a7835de41080582c2be3caf5981aa838140e97afa40ad652a0b544f83eb1833b0957dce26e47b0200eacd6046741e9ce2ec5beb6fb5e6335457844fb09477f83b050a96be7da043e17f3a9523567ed40e7a521f818813a8b8a72209f1442844843ccc7eb9805442570200bdafe0438d97ac36e773c7162028d65844c4d463e2420aa2228c6e50dc2743c3d6c72d0d782a5173fe7be2169c8a9f4ef8a7cf3e37165e8c61b89c346cdc6c1799d2b41054657374204b6579203120285253412988b804130102002205024d3c5c10021b03060b090807030206150802090a0b0416020301021e01021780000a0910a34d7e18c20c31bbb5b304009cc45fe610b641a2c146331be94dade0a396e73ca725e1b25c21708d9cab46ecca5ccebc23055879df8f99eea39b377962a400f2ebdc36a7c99c333d74aeba346315137c3ff9d0a09b0273299090343048afb8107cf94cbd1400e3026f0ccac7ecebbc4d78588eb3e478fe2754d3ca664bcf3eac96ca4a6b0c8d7df5102f60f6b00200009d01d8044d3c5c10010400b201df61d67487301f11879d514f4248ade90c8f68c7af1284c161098de4c28c2850f1ec7b8e30f959793e571542ffc6532189409cb51c3d30dad78c4ad5165eda18b20d9826d8707d0f742e2ab492103a85bbd9ddf4f5720f6de7064feb0d39ee002219765bb07bcfb8b877f47abe270ddeda4f676108cecb6b9bb2ad484a4f00110100010003fd17a7490c22a79c59281fb7b20f5e6553ec0c1637ae382e8adaea295f50241037f8997cf42c1ce26417e015091451b15424b2c59eb8d4161b0975630408e394d3b00f88d4b4e18e2cc85e8251d4753a27c639c83f5ad4a571c4f19d7cd460b9b73c25ade730c99df09637bd173d8e3e981ac64432078263bb6dc30d3e974150dd0200d0ee05be3d4604d2146fb0457f31ba17c057560785aa804e8ca5530a7cd81d3440d0f4ba6851efcfd3954b7e68908fc0ba47f7ac37bf559c6c168b70d3a7c8cd0200da1c677c4bce06a068070f2b3733b0a714e88d62aa3f9a26c6f5216d48d5c2b5624144f3807c0df30be66b3268eeeca4df1fbded58faf49fc95dc3c35f134f8b01fd1396b6c0fc1b6c4f0eb8f5e44b8eace1e6073e20d0b8bc5385f86f1cf3f050f66af789f3ef1fc107b7f4421e19e0349c730c68f0a226981f4e889054fdb4dc149e8e889f04180102000905024d3c5c10021b0c000a0910a34d7e18c20c31bb1a03040085c8d62e16d05dc4e9dad64953c8a2eed8b6c12f92b1575eeaa6dcf7be9473dd5b24b37b6dffbb4e7c99ed1bd3cb11634be19b3e6e207bed7505c7ca111ccf47cb323bf1f8851eb6360e8034cbff8dd149993c959de89f8f77f38e7e98b8e3076323aa719328e2b408db5ec0d03936efd57422ba04f925cdc7b4c1af7590e40ab00200009501fe044d3c5c33010400b488c3e5f83f4d561f317817538d9d0397981e9aef1321ca68ebfae1cf8b7d388e19f4b5a24a82e2fbbf1c6c26557a6c5845307a03d815756f564ac7325b02bc83e87d5480a8fae848f07cb891f2d51ce7df83dcafdc12324517c86d472cc0ee10d47a68fd1d9ae49a6c19bbd36d82af597a0d88cc9c49de9df4e696fc1f0b5d0011010001fe030302e9030f3c783e14856063f16938530e148bc57a7aa3f3e4f90df9dceccdc779bc0835e1ad3d006e4a8d7b36d08b8e0de5a0d947254ecfbd22037e6572b426bcfdc517796b224b0036ff90bc574b5509bede85512f2eefb520fb4b02aa523ba739bff424a6fe81c5041f253f8d757e69a503d3563a104d0d49e9e890b9d0c26f96b55b743883b472caa7050c4acfd4a21f875bdf1258d88bd61224d303dc9df77f743137d51e6d5246b88c406780528fd9a3e15bab5452e5b93970d9dcc79f48b38651b9f15bfbcf6da452837e9cc70683d1bdca94507870f743e4ad902005812488dd342f836e72869afd00ce1850eea4cfa53ce10e3608e13d3c149394ee3cbd0e23d018fcbcb6e2ec5a1a22972d1d462ca05355d0d290dd2751e550d5efb38c6c89686344df64852bf4ff86638708f644e8ec6bd4af9b50d8541cb91891a431326ab2e332faa7ae86cfb6e0540aa63160c1e5cdd5a4add518b303fff0a20117c6bc77f7cfbaf36b04c865c6c2b42754657374204b6579203220285253412c20656e637279707465642070726976617465206b65792988b804130102002205024d3c5c33021b03060b090807030206150802090a0b0416020301021e01021780000a0910d4984f961e35246b98940400908a73b6a6169f700434f076c6c79015a49bee37130eaf23aaa3cfa9ce60bfe4acaa7bc95f1146ada5867e0079babb38804891f4f0b8ebca57a86b249dee786161a755b7a342e68ccf3f78ed6440a93a6626beb9a37aa66afcd4f888790cb4bb46d94a4ae3eb3d7d3e6b00f6bfec940303e89ec5b32a1eaaacce66497d539328b00200009d01fe044d3c5c33010400a4e913f9442abcc7f1804ccab27d2f787ffa592077ca935a8bb23165bd8d57576acac647cc596b2c3f814518cc8c82953c7a4478f32e0cf645630a5ba38d9618ef2bc3add69d459ae3dece5cab778938d988239f8c5ae437807075e06c828019959c644ff05ef6a5a1dab72227c98e3a040b0cf219026640698d7a13d8538a570011010001fe030302e9030f3c783e148560f936097339ae381d63116efcf802ff8b1c9360767db5219cc987375702a4123fd8657d3e22700f23f95020d1b261eda5257e9a72f9a918e8ef22dd5b3323ae03bbc1923dd224db988cadc16acc04b120a9f8b7e84da9716c53e0334d7b66586ddb9014df604b41be1e960dcfcbc96f4ed150a1a0dd070b9eb14276b9b6be413a769a75b519a53d3ecc0c220e85cd91ca354d57e7344517e64b43b6e29823cbd87eae26e2b2e78e6dedfbb76e3e9f77bcb844f9a8932eb3db2c3f9e44316e6f5d60e9e2a56e46b72abe6b06dc9a31cc63f10023d1f5e12d2a3ee93b675c96f504af0001220991c88db759e231b3320dcedf814dcf723fd9857e3d72d66a0f2af26950b915abdf56c1596f46a325bf17ad4810d3535fb02a259b247ac3dbd4cc3ecf9c51b6c07cebb009c1506fba0a89321ec8683e3fd009a6e551d50243e2d5092fefb3321083a4bad91320dc624bd6b5dddf93553e3d53924c05bfebec1fb4bd47e89a1a889f04180102000905024d3c5c33021b0c000a0910d4984f961e35246b26c703ff7ee29ef53bc1ae1ead533c408fa136db508434e233d6e62be621e031e5940bbd4c08142aed0f82217e7c3e1ec8de574bc06ccf3c36633be41ad78a9eacd209f861cae7b064100758545cc9dd83db71806dc1cfd5fb9ae5c7474bba0c19c44034ae61bae5eca379383339dece94ff56ff7aa44a582f3e5c38f45763af577c0934b0020000"
+const dsaElGamalTestKeysHex = "9501e1044dfcb16a110400aa3e5c1a1f43dd28c2ffae8abf5cfce555ee874134d8ba0a0f7b868ce2214beddc74e5e1e21ded354a95d18acdaf69e5e342371a71fbb9093162e0c5f3427de413a7f2c157d83f5cd2f9d791256dc4f6f0e13f13c3302af27f2384075ab3021dff7a050e14854bbde0a1094174855fc02f0bae8e00a340d94a1f22b32e48485700a0cec672ac21258fb95f61de2ce1af74b2c4fa3e6703ff698edc9be22c02ae4d916e4fa223f819d46582c0516235848a77b577ea49018dcd5e9e15cff9dbb4663a1ae6dd7580fa40946d40c05f72814b0f88481207e6c0832c3bded4853ebba0a7e3bd8e8c66df33d5a537cd4acf946d1080e7a3dcea679cb2b11a72a33a2b6a9dc85f466ad2ddf4c3db6283fa645343286971e3dd700703fc0c4e290d45767f370831a90187e74e9972aae5bff488eeff7d620af0362bfb95c1a6c3413ab5d15a2e4139e5d07a54d72583914661ed6a87cce810be28a0aa8879a2dd39e52fb6fe800f4f181ac7e328f740cde3d09a05cecf9483e4cca4253e60d4429ffd679d9996a520012aad119878c941e3cf151459873bdfc2a9563472fe0303027a728f9feb3b864260a1babe83925ce794710cfd642ee4ae0e5b9d74cee49e9c67b6cd0ea5dfbb582132195a121356a1513e1bca73e5b80c58c7ccb4164453412f456c47616d616c2054657374204b65792031886204131102002205024dfcb16a021b03060b090807030206150802090a0b0416020301021e01021780000a091033af447ccd759b09fadd00a0b8fd6f5a790bad7e9f2dbb7632046dc4493588db009c087c6a9ba9f7f49fab221587a74788c00db4889ab00200009d0157044dfcb16a1004008dec3f9291205255ccff8c532318133a6840739dd68b03ba942676f9038612071447bf07d00d559c5c0875724ea16a4c774f80d8338b55fca691a0522e530e604215b467bbc9ccfd483a1da99d7bc2648b4318fdbd27766fc8bfad3fddb37c62b8ae7ccfe9577e9b8d1e77c1d417ed2c2ef02d52f4da11600d85d3229607943700030503ff506c94c87c8cab778e963b76cf63770f0a79bf48fb49d3b4e52234620fc9f7657f9f8d56c96a2b7c7826ae6b57ebb2221a3fe154b03b6637cea7e6d98e3e45d87cf8dc432f723d3d71f89c5192ac8d7290684d2c25ce55846a80c9a7823f6acd9bb29fa6cd71f20bc90eccfca20451d0c976e460e672b000df49466408d527affe0303027a728f9feb3b864260abd761730327bca2aaa4ea0525c175e92bf240682a0e83b226f97ecb2e935b62c9a133858ce31b271fa8eb41f6a1b3cd72a63025ce1a75ee4180dcc284884904181102000905024dfcb16a021b0c000a091033af447ccd759b09dd0b009e3c3e7296092c81bee5a19929462caaf2fff3ae26009e218c437a2340e7ea628149af1ec98ec091a43992b00200009501e1044dfcb1be1104009f61faa61aa43df75d128cbe53de528c4aec49ce9360c992e70c77072ad5623de0a3a6212771b66b39a30dad6781799e92608316900518ec01184a85d872365b7d2ba4bacfb5882ea3c2473d3750dc6178cc1cf82147fb58caa28b28e9f12f6d1efcb0534abed644156c91cca4ab78834268495160b2400bc422beb37d237c2300a0cac94911b6d493bda1e1fbc6feeca7cb7421d34b03fe22cec6ccb39675bb7b94a335c2b7be888fd3906a1125f33301d8aa6ec6ee6878f46f73961c8d57a3e9544d8ef2a2cbfd4d52da665b1266928cfe4cb347a58c412815f3b2d2369dec04b41ac9a71cc9547426d5ab941cccf3b18575637ccfb42df1a802df3cfe0a999f9e7109331170e3a221991bf868543960f8c816c28097e503fe319db10fb98049f3a57d7c80c420da66d56f3644371631fad3f0ff4040a19a4fedc2d07727a1b27576f75a4d28c47d8246f27071e12d7a8de62aad216ddbae6aa02efd6b8a3e2818cda48526549791ab277e447b3a36c57cefe9b592f5eab73959743fcc8e83cbefec03a329b55018b53eec196765ae40ef9e20521a603c551efe0303020950d53a146bf9c66034d00c23130cce95576a2ff78016ca471276e8227fb30b1ffbd92e61804fb0c3eff9e30b1a826ee8f3e4730b4d86273ca977b4164453412f456c47616d616c2054657374204b65792032886204131102002205024dfcb1be021b03060b090807030206150802090a0b0416020301021e01021780000a0910a86bf526325b21b22bd9009e34511620415c974750a20df5cb56b182f3b48e6600a0a9466cb1a1305a84953445f77d461593f1d42bc1b00200009d0157044dfcb1be1004009565a951da1ee87119d600c077198f1c1bceb0f7aa54552489298e41ff788fa8f0d43a69871f0f6f77ebdfb14a4260cf9fbeb65d5844b4272a1904dd95136d06c3da745dc46327dd44a0f16f60135914368c8039a34033862261806bb2c5ce1152e2840254697872c85441ccb7321431d75a747a4bfb1d2c66362b51ce76311700030503fc0ea76601c196768070b7365a200e6ddb09307f262d5f39eec467b5f5784e22abdf1aa49226f59ab37cb49969d8f5230ea65caf56015abda62604544ed526c5c522bf92bed178a078789f6c807b6d34885688024a5bed9e9f8c58d11d4b82487b44c5f470c5606806a0443b79cadb45e0f897a561a53f724e5349b9267c75ca17fe0303020950d53a146bf9c660bc5f4ce8f072465e2d2466434320c1e712272fafc20e342fe7608101580fa1a1a367e60486a7cd1246b7ef5586cf5e10b32762b710a30144f12dd17dd4884904181102000905024dfcb1be021b0c000a0910a86bf526325b21b2904c00a0b2b66b4b39ccffda1d10f3ea8d58f827e30a8b8e009f4255b2d8112a184e40cde43a34e8655ca7809370b0020000"
+
const signedMessageHex = "a3019bc0cbccc0c4b8d8b74ee2108fe16ec6d3ca490cbe362d3f8333d3f352531472538b8b13d353b97232f352158c20943157c71c16064626063656269052062e4e01987e9b6fccff4b7df3a34c534b23e679cbec3bc0f8f6e64dfb4b55fe3f8efa9ce110ddb5cd79faf1d753c51aecfa669f7e7aa043436596cccc3359cb7dd6bbe9ecaa69e5989d9e57209571edc0b2fa7f57b9b79a64ee6e99ce1371395fee92fec2796f7b15a77c386ff668ee27f6d38f0baa6c438b561657377bf6acff3c5947befd7bf4c196252f1d6e5c524d0300"
const signedTextMessageHex = "a3019bc0cbccc8c4b8d8b74ee2108fe16ec6d36a250cbece0c178233d3f352531472538b8b13d35379b97232f352158ca0b4312f57c71c1646462606365626906a062e4e019811591798ff99bf8afee860b0d8a8c2a85c3387e3bcf0bb3b17987f2bbcfab2aa526d930cbfd3d98757184df3995c9f3e7790e36e3e9779f06089d4c64e9e47dd6202cb6e9bc73c5d11bb59fbaf89d22d8dc7cf199ddf17af96e77c5f65f9bbed56f427bd8db7af37f6c9984bf9385efaf5f184f986fb3e6adb0ecfe35bbf92d16a7aa2a344fb0bc52fb7624f0200"
const signedEncryptedMessageHex = "848c032a67d68660df41c70103ff5789d0de26b6a50c985a02a13131ca829c413a35d0e6fa8d6842599252162808ac7439c72151c8c6183e76923fe3299301414d0c25a2f06a2257db3839e7df0ec964773f6e4c4ac7ff3b48c444237166dd46ba8ff443a5410dc670cb486672fdbe7c9dfafb75b4fea83af3a204fe2a7dfa86bd20122b4f3d2646cbeecb8f7be8d2c03b018bd210b1d3791e1aba74b0f1034e122ab72e760492c192383cf5e20b5628bd043272d63df9b923f147eb6091cd897553204832aba48fec54aa447547bb16305a1024713b90e77fd0065f1918271947549205af3c74891af22ee0b56cd29bfec6d6e351901cd4ab3ece7c486f1e32a792d4e474aed98ee84b3f591c7dff37b64e0ecd68fd036d517e412dcadf85840ce184ad7921ad446c4ee28db80447aea1ca8d4f574db4d4e37688158ddd19e14ee2eab4873d46947d65d14a23e788d912cf9a19624ca7352469b72a83866b7c23cb5ace3deab3c7018061b0ba0f39ed2befe27163e5083cf9b8271e3e3d52cc7ad6e2a3bd81d4c3d7022f8d"
+const signedEncryptedMessage2Hex = "85010e03cf6a7abcd43e36731003fb057f5495b79db367e277cdbe4ab90d924ddee0c0381494112ff8c1238fb0184af35d1731573b01bc4c55ecacd2aafbe2003d36310487d1ecc9ac994f3fada7f9f7f5c3a64248ab7782906c82c6ff1303b69a84d9a9529c31ecafbcdb9ba87e05439897d87e8a2a3dec55e14df19bba7f7bd316291c002ae2efd24f83f9e3441203fc081c0c23dc3092a454ca8a082b27f631abf73aca341686982e8fbda7e0e7d863941d68f3de4a755c2964407f4b5e0477b3196b8c93d551dd23c8beef7d0f03fbb1b6066f78907faf4bf1677d8fcec72651124080e0b7feae6b476e72ab207d38d90b958759fdedfc3c6c35717c9dbfc979b3cfbbff0a76d24a5e57056bb88acbd2a901ef64bc6e4db02adc05b6250ff378de81dca18c1910ab257dff1b9771b85bb9bbe0a69f5989e6d1710a35e6dfcceb7d8fb5ccea8db3932b3d9ff3fe0d327597c68b3622aec8e3716c83a6c93f497543b459b58ba504ed6bcaa747d37d2ca746fe49ae0a6ce4a8b694234e941b5159ff8bd34b9023da2814076163b86f40eed7c9472f81b551452d5ab87004a373c0172ec87ea6ce42ccfa7dbdad66b745496c4873d8019e8c28d6b3"
+
const symmetricallyEncryptedCompressedHex = "8c0d04030302eb4a03808145d0d260c92f714339e13de5a79881216431925bf67ee2898ea61815f07894cd0703c50d0a76ef64d482196f47a8bc729af9b80bb6"
const dsaTestKeyHex = "9901a2044d6c49de110400cb5ce438cf9250907ac2ba5bf6547931270b89f7c4b53d9d09f4d0213a5ef2ec1f26806d3d259960f872a4a102ef1581ea3f6d6882d15134f21ef6a84de933cc34c47cc9106efe3bd84c6aec12e78523661e29bc1a61f0aab17fa58a627fd5fd33f5149153fbe8cd70edf3d963bc287ef875270ff14b5bfdd1bca4483793923b00a0fe46d76cb6e4cbdc568435cd5480af3266d610d303fe33ae8273f30a96d4d34f42fa28ce1112d425b2e3bf7ea553d526e2db6b9255e9dc7419045ce817214d1a0056dbc8d5289956a4b1b69f20f1105124096e6a438f41f2e2495923b0f34b70642607d45559595c7fe94d7fa85fc41bf7d68c1fd509ebeaa5f315f6059a446b9369c277597e4f474a9591535354c7e7f4fd98a08aa60400b130c24ff20bdfbf683313f5daebf1c9b34b3bdadfc77f2ddd72ee1fb17e56c473664bc21d66467655dd74b9005e3a2bacce446f1920cd7017231ae447b67036c9b431b8179deacd5120262d894c26bc015bffe3d827ba7087ad9b700d2ca1f6d16cc1786581e5dd065f293c31209300f9b0afcc3f7c08dd26d0a22d87580b4db41054657374204b65792033202844534129886204131102002205024d6c49de021b03060b090807030206150802090a0b0416020301021e01021780000a0910338934250ccc03607e0400a0bdb9193e8a6b96fc2dfc108ae848914b504481f100a09c4dc148cb693293a67af24dd40d2b13a9e36794"
diff --git a/libgo/go/crypto/openpgp/s2k/s2k.go b/libgo/go/crypto/openpgp/s2k/s2k.go
index 93b7582..da926a7 100644
--- a/libgo/go/crypto/openpgp/s2k/s2k.go
+++ b/libgo/go/crypto/openpgp/s2k/s2k.go
@@ -90,7 +90,7 @@ func Parse(r io.Reader) (f func(out, in []byte), err os.Error) {
}
h := hash.New()
if h == nil {
- return nil, error.UnsupportedError("hash not availible: " + strconv.Itoa(int(hash)))
+ return nil, error.UnsupportedError("hash not available: " + strconv.Itoa(int(hash)))
}
switch buf[0] {
@@ -123,6 +123,26 @@ func Parse(r io.Reader) (f func(out, in []byte), err os.Error) {
return nil, error.UnsupportedError("S2K function")
}
+// Serialize salts and stretches the given passphrase and writes the resulting
+// key into key. It also serializes an S2K descriptor to w.
+func Serialize(w io.Writer, key []byte, rand io.Reader, passphrase []byte) os.Error {
+ var buf [11]byte
+ buf[0] = 3 /* iterated and salted */
+ buf[1], _ = HashToHashId(crypto.SHA1)
+ salt := buf[2:10]
+ if _, err := io.ReadFull(rand, salt); err != nil {
+ return err
+ }
+ const count = 65536 // this is the default in gpg
+ buf[10] = 96 // 65536 iterations
+ if _, err := w.Write(buf[:]); err != nil {
+ return err
+ }
+
+ Iterated(key, crypto.SHA1.New(), passphrase, salt, count)
+ return nil
+}
+
// hashToHashIdMapping contains pairs relating OpenPGP's hash identifier with
// Go's crypto.Hash type. See RFC 4880, section 9.4.
var hashToHashIdMapping = []struct {
diff --git a/libgo/go/crypto/openpgp/s2k/s2k_test.go b/libgo/go/crypto/openpgp/s2k/s2k_test.go
index 75bc47e..ec4012c 100644
--- a/libgo/go/crypto/openpgp/s2k/s2k_test.go
+++ b/libgo/go/crypto/openpgp/s2k/s2k_test.go
@@ -7,6 +7,7 @@ package s2k
import (
"bytes"
"crypto/sha1"
+ "crypto/rand"
"encoding/hex"
"testing"
)
@@ -36,7 +37,6 @@ func TestSalted(t *testing.T) {
}
}
-
var iteratedTests = []struct {
in, out string
}{
@@ -62,7 +62,6 @@ func TestIterated(t *testing.T) {
}
}
-
var parseTests = []struct {
spec, in, out string
}{
@@ -95,3 +94,25 @@ func TestParse(t *testing.T) {
}
}
}
+
+func TestSerialize(t *testing.T) {
+ buf := bytes.NewBuffer(nil)
+ key := make([]byte, 16)
+ passphrase := []byte("testing")
+ err := Serialize(buf, key, rand.Reader, passphrase)
+ if err != nil {
+ t.Errorf("failed to serialize: %s", err)
+ return
+ }
+
+ f, err := Parse(buf)
+ if err != nil {
+ t.Errorf("failed to reparse: %s", err)
+ return
+ }
+ key2 := make([]byte, len(key))
+ f(key2, passphrase)
+ if !bytes.Equal(key2, key) {
+ t.Errorf("keys don't match: %x (serialied) vs %x (parsed)", key, key2)
+ }
+}
diff --git a/libgo/go/crypto/openpgp/write.go b/libgo/go/crypto/openpgp/write.go
index ef7b112..9884472c 100644
--- a/libgo/go/crypto/openpgp/write.go
+++ b/libgo/go/crypto/openpgp/write.go
@@ -6,12 +6,13 @@ package openpgp
import (
"crypto"
- "crypto/dsa"
"crypto/openpgp/armor"
"crypto/openpgp/error"
"crypto/openpgp/packet"
- "crypto/rsa"
+ "crypto/openpgp/s2k"
+ "crypto/rand"
_ "crypto/sha256"
+ "hash"
"io"
"os"
"strconv"
@@ -77,20 +78,231 @@ func detachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.S
}
io.Copy(wrappedHash, message)
- switch signer.PrivateKey.PubKeyAlgo {
- case packet.PubKeyAlgoRSA, packet.PubKeyAlgoRSASignOnly:
- priv := signer.PrivateKey.PrivateKey.(*rsa.PrivateKey)
- err = sig.SignRSA(h, priv)
- case packet.PubKeyAlgoDSA:
- priv := signer.PrivateKey.PrivateKey.(*dsa.PrivateKey)
- err = sig.SignDSA(h, priv)
- default:
- err = error.UnsupportedError("public key algorithm: " + strconv.Itoa(int(sig.PubKeyAlgo)))
+ err = sig.Sign(h, signer.PrivateKey)
+ if err != nil {
+ return
+ }
+
+ return sig.Serialize(w)
+}
+
+// FileHints contains metadata about encrypted files. This metadata is, itself,
+// encrypted.
+type FileHints struct {
+ // IsBinary can be set to hint that the contents are binary data.
+ IsBinary bool
+ // FileName hints at the name of the file that should be written. It's
+ // truncated to 255 bytes if longer. It may be empty to suggest that the
+ // file should not be written to disk. It may be equal to "_CONSOLE" to
+ // suggest the data should not be written to disk.
+ FileName string
+ // EpochSeconds contains the modification time of the file, or 0 if not applicable.
+ EpochSeconds uint32
+}
+
+// SymmetricallyEncrypt acts like gpg -c: it encrypts a file with a passphrase.
+// The resulting WriteCloser must be closed after the contents of the file have
+// been written.
+func SymmetricallyEncrypt(ciphertext io.Writer, passphrase []byte, hints *FileHints) (plaintext io.WriteCloser, err os.Error) {
+ if hints == nil {
+ hints = &FileHints{}
}
+ key, err := packet.SerializeSymmetricKeyEncrypted(ciphertext, rand.Reader, passphrase, packet.CipherAES128)
if err != nil {
return
}
+ w, err := packet.SerializeSymmetricallyEncrypted(ciphertext, packet.CipherAES128, key)
+ if err != nil {
+ return
+ }
+ return packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, hints.EpochSeconds)
+}
- return sig.Serialize(w)
+// intersectPreferences mutates and returns a prefix of a that contains only
+// the values in the intersection of a and b. The order of a is preserved.
+func intersectPreferences(a []uint8, b []uint8) (intersection []uint8) {
+ var j int
+ for _, v := range a {
+ for _, v2 := range b {
+ if v == v2 {
+ a[j] = v
+ j++
+ break
+ }
+ }
+ }
+
+ return a[:j]
+}
+
+func hashToHashId(h crypto.Hash) uint8 {
+ v, ok := s2k.HashToHashId(h)
+ if !ok {
+ panic("tried to convert unknown hash")
+ }
+ return v
+}
+
+// Encrypt encrypts a message to a number of recipients and, optionally, signs
+// it. hints contains optional information, that is also encrypted, that aids
+// the recipients in processing the message. The resulting WriteCloser must
+// be closed after the contents of the file have been written.
+func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHints) (plaintext io.WriteCloser, err os.Error) {
+ var signer *packet.PrivateKey
+ if signed != nil {
+ signer = signed.signingKey().PrivateKey
+ if signer == nil || signer.Encrypted {
+ return nil, error.InvalidArgumentError("signing key must be decrypted")
+ }
+ }
+
+ // These are the possible ciphers that we'll use for the message.
+ candidateCiphers := []uint8{
+ uint8(packet.CipherAES128),
+ uint8(packet.CipherAES256),
+ uint8(packet.CipherCAST5),
+ }
+ // These are the possible hash functions that we'll use for the signature.
+ candidateHashes := []uint8{
+ hashToHashId(crypto.SHA256),
+ hashToHashId(crypto.SHA512),
+ hashToHashId(crypto.SHA1),
+ hashToHashId(crypto.RIPEMD160),
+ }
+ // In the event that a recipient doesn't specify any supported ciphers
+ // or hash functions, these are the ones that we assume that every
+ // implementation supports.
+ defaultCiphers := candidateCiphers[len(candidateCiphers)-1:]
+ defaultHashes := candidateHashes[len(candidateHashes)-1:]
+
+ encryptKeys := make([]Key, len(to))
+ for i := range to {
+ encryptKeys[i] = to[i].encryptionKey()
+ if encryptKeys[i].PublicKey == nil {
+ return nil, error.InvalidArgumentError("cannot encrypt a message to key id " + strconv.Uitob64(to[i].PrimaryKey.KeyId, 16) + " because it has no encryption keys")
+ }
+
+ sig := to[i].primaryIdentity().SelfSignature
+
+ preferredSymmetric := sig.PreferredSymmetric
+ if len(preferredSymmetric) == 0 {
+ preferredSymmetric = defaultCiphers
+ }
+ preferredHashes := sig.PreferredHash
+ if len(preferredHashes) == 0 {
+ preferredHashes = defaultHashes
+ }
+ candidateCiphers = intersectPreferences(candidateCiphers, preferredSymmetric)
+ candidateHashes = intersectPreferences(candidateHashes, preferredHashes)
+ }
+
+ if len(candidateCiphers) == 0 || len(candidateHashes) == 0 {
+ return nil, error.InvalidArgumentError("cannot encrypt because recipient set shares no common algorithms")
+ }
+
+ cipher := packet.CipherFunction(candidateCiphers[0])
+ hash, _ := s2k.HashIdToHash(candidateHashes[0])
+ symKey := make([]byte, cipher.KeySize())
+ if _, err := io.ReadFull(rand.Reader, symKey); err != nil {
+ return nil, err
+ }
+
+ for _, key := range encryptKeys {
+ if err := packet.SerializeEncryptedKey(ciphertext, rand.Reader, key.PublicKey, cipher, symKey); err != nil {
+ return nil, err
+ }
+ }
+
+ encryptedData, err := packet.SerializeSymmetricallyEncrypted(ciphertext, cipher, symKey)
+ if err != nil {
+ return
+ }
+
+ if signer != nil {
+ ops := &packet.OnePassSignature{
+ SigType: packet.SigTypeBinary,
+ Hash: hash,
+ PubKeyAlgo: signer.PubKeyAlgo,
+ KeyId: signer.KeyId,
+ IsLast: true,
+ }
+ if err := ops.Serialize(encryptedData); err != nil {
+ return nil, err
+ }
+ }
+
+ if hints == nil {
+ hints = &FileHints{}
+ }
+
+ w := encryptedData
+ if signer != nil {
+ // If we need to write a signature packet after the literal
+ // data then we need to stop literalData from closing
+ // encryptedData.
+ w = noOpCloser{encryptedData}
+
+ }
+ literalData, err := packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, hints.EpochSeconds)
+ if err != nil {
+ return nil, err
+ }
+
+ if signer != nil {
+ return signatureWriter{encryptedData, literalData, hash, hash.New(), signer}, nil
+ }
+ return literalData, nil
+}
+
+// signatureWriter hashes the contents of a message while passing it along to
+// literalData. When closed, it closes literalData, writes a signature packet
+// to encryptedData and then also closes encryptedData.
+type signatureWriter struct {
+ encryptedData io.WriteCloser
+ literalData io.WriteCloser
+ hashType crypto.Hash
+ h hash.Hash
+ signer *packet.PrivateKey
+}
+
+func (s signatureWriter) Write(data []byte) (int, os.Error) {
+ s.h.Write(data)
+ return s.literalData.Write(data)
+}
+
+func (s signatureWriter) Close() os.Error {
+ sig := &packet.Signature{
+ SigType: packet.SigTypeBinary,
+ PubKeyAlgo: s.signer.PubKeyAlgo,
+ Hash: s.hashType,
+ CreationTime: uint32(time.Seconds()),
+ IssuerKeyId: &s.signer.KeyId,
+ }
+
+ if err := sig.Sign(s.h, s.signer); err != nil {
+ return err
+ }
+ if err := s.literalData.Close(); err != nil {
+ return err
+ }
+ if err := sig.Serialize(s.encryptedData); err != nil {
+ return err
+ }
+ return s.encryptedData.Close()
+}
+
+// noOpCloser is like an ioutil.NopCloser, but for an io.Writer.
+// TODO: we have two of these in OpenPGP packages alone. This probably needs
+// to be promoted somewhere more common.
+type noOpCloser struct {
+ w io.Writer
+}
+
+func (c noOpCloser) Write(data []byte) (n int, err os.Error) {
+ return c.w.Write(data)
+}
+
+func (c noOpCloser) Close() os.Error {
+ return nil
}
diff --git a/libgo/go/crypto/openpgp/write_test.go b/libgo/go/crypto/openpgp/write_test.go
index 42cd0d2..c542dfa 100644
--- a/libgo/go/crypto/openpgp/write_test.go
+++ b/libgo/go/crypto/openpgp/write_test.go
@@ -6,7 +6,12 @@ package openpgp
import (
"bytes"
+ "crypto/rand"
+ "os"
+ "io"
+ "io/ioutil"
"testing"
+ "time"
)
func TestSignDetached(t *testing.T) {
@@ -44,3 +49,185 @@ func TestSignDetachedDSA(t *testing.T) {
testDetachedSignature(t, kring, out, signedInput, "check", testKey3KeyId)
}
+
+func TestNewEntity(t *testing.T) {
+ if testing.Short() {
+ return
+ }
+
+ e, err := NewEntity(rand.Reader, time.Seconds(), "Test User", "test", "test@example.com")
+ if err != nil {
+ t.Errorf("failed to create entity: %s", err)
+ return
+ }
+
+ w := bytes.NewBuffer(nil)
+ if err := e.SerializePrivate(w); err != nil {
+ t.Errorf("failed to serialize entity: %s", err)
+ return
+ }
+ serialized := w.Bytes()
+
+ el, err := ReadKeyRing(w)
+ if err != nil {
+ t.Errorf("failed to reparse entity: %s", err)
+ return
+ }
+
+ if len(el) != 1 {
+ t.Errorf("wrong number of entities found, got %d, want 1", len(el))
+ }
+
+ w = bytes.NewBuffer(nil)
+ if err := e.SerializePrivate(w); err != nil {
+ t.Errorf("failed to serialize entity second time: %s", err)
+ return
+ }
+
+ if !bytes.Equal(w.Bytes(), serialized) {
+ t.Errorf("results differed")
+ }
+}
+
+func TestSymmetricEncryption(t *testing.T) {
+ buf := new(bytes.Buffer)
+ plaintext, err := SymmetricallyEncrypt(buf, []byte("testing"), nil)
+ if err != nil {
+ t.Errorf("error writing headers: %s", err)
+ return
+ }
+ message := []byte("hello world\n")
+ _, err = plaintext.Write(message)
+ if err != nil {
+ t.Errorf("error writing to plaintext writer: %s", err)
+ }
+ err = plaintext.Close()
+ if err != nil {
+ t.Errorf("error closing plaintext writer: %s", err)
+ }
+
+ md, err := ReadMessage(buf, nil, func(keys []Key, symmetric bool) ([]byte, os.Error) {
+ return []byte("testing"), nil
+ })
+ if err != nil {
+ t.Errorf("error rereading message: %s", err)
+ }
+ messageBuf := bytes.NewBuffer(nil)
+ _, err = io.Copy(messageBuf, md.UnverifiedBody)
+ if err != nil {
+ t.Errorf("error rereading message: %s", err)
+ }
+ if !bytes.Equal(message, messageBuf.Bytes()) {
+ t.Errorf("recovered message incorrect got '%s', want '%s'", messageBuf.Bytes(), message)
+ }
+}
+
+var testEncryptionTests = []struct {
+ keyRingHex string
+ isSigned bool
+}{
+ {
+ testKeys1And2PrivateHex,
+ false,
+ },
+ {
+ testKeys1And2PrivateHex,
+ true,
+ },
+ {
+ dsaElGamalTestKeysHex,
+ false,
+ },
+ {
+ dsaElGamalTestKeysHex,
+ true,
+ },
+}
+
+func TestEncryption(t *testing.T) {
+ for i, test := range testEncryptionTests {
+ kring, _ := ReadKeyRing(readerFromHex(test.keyRingHex))
+
+ passphrase := []byte("passphrase")
+ for _, entity := range kring {
+ if entity.PrivateKey != nil && entity.PrivateKey.Encrypted {
+ err := entity.PrivateKey.Decrypt(passphrase)
+ if err != nil {
+ t.Errorf("#%d: failed to decrypt key", i)
+ }
+ }
+ for _, subkey := range entity.Subkeys {
+ if subkey.PrivateKey != nil && subkey.PrivateKey.Encrypted {
+ err := subkey.PrivateKey.Decrypt(passphrase)
+ if err != nil {
+ t.Errorf("#%d: failed to decrypt subkey", i)
+ }
+ }
+ }
+ }
+
+ var signed *Entity
+ if test.isSigned {
+ signed = kring[0]
+ }
+
+ buf := new(bytes.Buffer)
+ w, err := Encrypt(buf, kring[:1], signed, nil /* no hints */ )
+ if err != nil {
+ t.Errorf("#%d: error in Encrypt: %s", i, err)
+ continue
+ }
+
+ const message = "testing"
+ _, err = w.Write([]byte(message))
+ if err != nil {
+ t.Errorf("#%d: error writing plaintext: %s", i, err)
+ continue
+ }
+ err = w.Close()
+ if err != nil {
+ t.Errorf("#%d: error closing WriteCloser: %s", i, err)
+ continue
+ }
+
+ md, err := ReadMessage(buf, kring, nil /* no prompt */ )
+ if err != nil {
+ t.Errorf("#%d: error reading message: %s", i, err)
+ continue
+ }
+
+ if test.isSigned {
+ expectedKeyId := kring[0].signingKey().PublicKey.KeyId
+ if md.SignedByKeyId != expectedKeyId {
+ t.Errorf("#%d: message signed by wrong key id, got: %d, want: %d", i, *md.SignedBy, expectedKeyId)
+ }
+ if md.SignedBy == nil {
+ t.Errorf("#%d: failed to find the signing Entity", i)
+ }
+ }
+
+ plaintext, err := ioutil.ReadAll(md.UnverifiedBody)
+ if err != nil {
+ t.Errorf("#%d: error reading encrypted contents: %s", i, err)
+ continue
+ }
+
+ expectedKeyId := kring[0].encryptionKey().PublicKey.KeyId
+ if len(md.EncryptedToKeyIds) != 1 || md.EncryptedToKeyIds[0] != expectedKeyId {
+ t.Errorf("#%d: expected message to be encrypted to %v, but got %#v", i, expectedKeyId, md.EncryptedToKeyIds)
+ }
+
+ if string(plaintext) != message {
+ t.Errorf("#%d: got: %s, want: %s", i, string(plaintext), message)
+ }
+
+ if test.isSigned {
+ if md.SignatureError != nil {
+ t.Errorf("#%d: signature error: %s", i, err)
+ }
+ if md.Signature == nil {
+ t.Error("signature missing")
+ }
+ }
+ }
+}
diff --git a/libgo/go/crypto/rand/rand_windows.go b/libgo/go/crypto/rand/rand_windows.go
index 281d6dc..0eab6b2 100644
--- a/libgo/go/crypto/rand/rand_windows.go
+++ b/libgo/go/crypto/rand/rand_windows.go
@@ -19,7 +19,7 @@ func init() { Reader = &rngReader{} }
// A rngReader satisfies reads by reading from the Windows CryptGenRandom API.
type rngReader struct {
- prov uint32
+ prov syscall.Handle
mu sync.Mutex
}
diff --git a/libgo/go/crypto/rand/util.go b/libgo/go/crypto/rand/util.go
new file mode 100644
index 0000000..7702847
--- /dev/null
+++ b/libgo/go/crypto/rand/util.go
@@ -0,0 +1,80 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rand
+
+import (
+ "big"
+ "io"
+ "os"
+)
+
+// Prime returns a number, p, of the given size, such that p is prime
+// with high probability.
+func Prime(rand io.Reader, bits int) (p *big.Int, err os.Error) {
+ if bits < 1 {
+ err = os.EINVAL
+ }
+
+ b := uint(bits % 8)
+ if b == 0 {
+ b = 8
+ }
+
+ bytes := make([]byte, (bits+7)/8)
+ p = new(big.Int)
+
+ for {
+ _, err = io.ReadFull(rand, bytes)
+ if err != nil {
+ return nil, err
+ }
+
+ // Clear bits in the first byte to make sure the candidate has a size <= bits.
+ bytes[0] &= uint8(int(1<<b) - 1)
+ // Don't let the value be too small, i.e, set the most significant bit.
+ bytes[0] |= 1 << (b - 1)
+ // Make the value odd since an even number this large certainly isn't prime.
+ bytes[len(bytes)-1] |= 1
+
+ p.SetBytes(bytes)
+ if big.ProbablyPrime(p, 20) {
+ return
+ }
+ }
+
+ return
+}
+
+// Int returns a uniform random value in [0, max).
+func Int(rand io.Reader, max *big.Int) (n *big.Int, err os.Error) {
+ k := (max.BitLen() + 7) / 8
+
+ // b is the number of bits in the most significant byte of max.
+ b := uint(max.BitLen() % 8)
+ if b == 0 {
+ b = 8
+ }
+
+ bytes := make([]byte, k)
+ n = new(big.Int)
+
+ for {
+ _, err = io.ReadFull(rand, bytes)
+ if err != nil {
+ return nil, err
+ }
+
+ // Clear bits in the first byte to increase the probability
+ // that the candidate is < max.
+ bytes[0] &= uint8(int(1<<b) - 1)
+
+ n.SetBytes(bytes)
+ if n.Cmp(max) < 0 {
+ return
+ }
+ }
+
+ return
+}
diff --git a/libgo/go/crypto/rsa/pkcs1v15.go b/libgo/go/crypto/rsa/pkcs1v15.go
index 3defa62..6006231 100644
--- a/libgo/go/crypto/rsa/pkcs1v15.go
+++ b/libgo/go/crypto/rsa/pkcs1v15.go
@@ -232,11 +232,11 @@ func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte)
func pkcs1v15HashInfo(hash crypto.Hash, inLen int) (hashLen int, prefix []byte, err os.Error) {
hashLen = hash.Size()
if inLen != hashLen {
- return 0, nil, os.ErrorString("input must be hashed message")
+ return 0, nil, os.NewError("input must be hashed message")
}
prefix, ok := hashPrefixes[hash]
if !ok {
- return 0, nil, os.ErrorString("unsupported hash function")
+ return 0, nil, os.NewError("unsupported hash function")
}
return
}
diff --git a/libgo/go/crypto/rsa/rsa.go b/libgo/go/crypto/rsa/rsa.go
index e1813db..6957659 100644
--- a/libgo/go/crypto/rsa/rsa.go
+++ b/libgo/go/crypto/rsa/rsa.go
@@ -9,6 +9,7 @@ package rsa
import (
"big"
+ "crypto/rand"
"crypto/subtle"
"hash"
"io"
@@ -18,69 +19,6 @@ import (
var bigZero = big.NewInt(0)
var bigOne = big.NewInt(1)
-// randomPrime returns a number, p, of the given size, such that p is prime
-// with high probability.
-func randomPrime(rand io.Reader, bits int) (p *big.Int, err os.Error) {
- if bits < 1 {
- err = os.EINVAL
- }
-
- bytes := make([]byte, (bits+7)/8)
- p = new(big.Int)
-
- for {
- _, err = io.ReadFull(rand, bytes)
- if err != nil {
- return
- }
-
- // Don't let the value be too small.
- bytes[0] |= 0x80
- // Make the value odd since an even number this large certainly isn't prime.
- bytes[len(bytes)-1] |= 1
-
- p.SetBytes(bytes)
- if big.ProbablyPrime(p, 20) {
- return
- }
- }
-
- return
-}
-
-// randomNumber returns a uniform random value in [0, max).
-func randomNumber(rand io.Reader, max *big.Int) (n *big.Int, err os.Error) {
- k := (max.BitLen() + 7) / 8
-
- // r is the number of bits in the used in the most significant byte of
- // max.
- r := uint(max.BitLen() % 8)
- if r == 0 {
- r = 8
- }
-
- bytes := make([]byte, k)
- n = new(big.Int)
-
- for {
- _, err = io.ReadFull(rand, bytes)
- if err != nil {
- return
- }
-
- // Clear bits in the first byte to increase the probability
- // that the candidate is < max.
- bytes[0] &= uint8(int(1<<r) - 1)
-
- n.SetBytes(bytes)
- if n.Cmp(max) < 0 {
- return
- }
- }
-
- return
-}
-
// A PublicKey represents the public part of an RSA key.
type PublicKey struct {
N *big.Int // modulus
@@ -94,7 +32,7 @@ type PrivateKey struct {
Primes []*big.Int // prime factors of N, has >= 2 elements.
// Precomputed contains precomputed values that speed up private
- // operations, if availible.
+ // operations, if available.
Precomputed PrecomputedValues
}
@@ -126,7 +64,7 @@ func (priv *PrivateKey) Validate() os.Error {
// easy for an attack to generate composites that pass this test.
for _, prime := range priv.Primes {
if !big.ProbablyPrime(prime, 20) {
- return os.ErrorString("Prime factor is composite")
+ return os.NewError("prime factor is composite")
}
}
@@ -136,7 +74,7 @@ func (priv *PrivateKey) Validate() os.Error {
modulus.Mul(modulus, prime)
}
if modulus.Cmp(priv.N) != 0 {
- return os.ErrorString("invalid modulus")
+ return os.NewError("invalid modulus")
}
// Check that e and totient(Πprimes) are coprime.
totient := new(big.Int).Set(bigOne)
@@ -150,20 +88,20 @@ func (priv *PrivateKey) Validate() os.Error {
y := new(big.Int)
big.GcdInt(gcd, x, y, totient, e)
if gcd.Cmp(bigOne) != 0 {
- return os.ErrorString("invalid public exponent E")
+ return os.NewError("invalid public exponent E")
}
// Check that de ≡ 1 (mod totient(Πprimes))
de := new(big.Int).Mul(priv.D, e)
de.Mod(de, totient)
if de.Cmp(bigOne) != 0 {
- return os.ErrorString("invalid private exponent D")
+ return os.NewError("invalid private exponent D")
}
return nil
}
// GenerateKey generates an RSA keypair of the given bit size.
-func GenerateKey(rand io.Reader, bits int) (priv *PrivateKey, err os.Error) {
- return GenerateMultiPrimeKey(rand, 2, bits)
+func GenerateKey(random io.Reader, bits int) (priv *PrivateKey, err os.Error) {
+ return GenerateMultiPrimeKey(random, 2, bits)
}
// GenerateMultiPrimeKey generates a multi-prime RSA keypair of the given bit
@@ -176,7 +114,7 @@ func GenerateKey(rand io.Reader, bits int) (priv *PrivateKey, err os.Error) {
//
// [1] US patent 4405829 (1972, expired)
// [2] http://www.cacr.math.uwaterloo.ca/techreports/2006/cacr2006-16.pdf
-func GenerateMultiPrimeKey(rand io.Reader, nprimes int, bits int) (priv *PrivateKey, err os.Error) {
+func GenerateMultiPrimeKey(random io.Reader, nprimes int, bits int) (priv *PrivateKey, err os.Error) {
priv = new(PrivateKey)
// Smaller public exponents lead to faster public key
// operations. Since the exponent must be coprime to
@@ -189,7 +127,7 @@ func GenerateMultiPrimeKey(rand io.Reader, nprimes int, bits int) (priv *Private
priv.E = 3
if nprimes < 2 {
- return nil, os.ErrorString("rsa.GenerateMultiPrimeKey: nprimes must be >= 2")
+ return nil, os.NewError("rsa.GenerateMultiPrimeKey: nprimes must be >= 2")
}
primes := make([]*big.Int, nprimes)
@@ -198,7 +136,7 @@ NextSetOfPrimes:
for {
todo := bits
for i := 0; i < nprimes; i++ {
- primes[i], err = randomPrime(rand, todo/(nprimes-i))
+ primes[i], err = rand.Prime(random, todo/(nprimes-i))
if err != nil {
return nil, err
}
@@ -293,7 +231,7 @@ func encrypt(c *big.Int, pub *PublicKey, m *big.Int) *big.Int {
// EncryptOAEP encrypts the given message with RSA-OAEP.
// The message must be no longer than the length of the public modulus less
// twice the hash length plus 2.
-func EncryptOAEP(hash hash.Hash, rand io.Reader, pub *PublicKey, msg []byte, label []byte) (out []byte, err os.Error) {
+func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, label []byte) (out []byte, err os.Error) {
hash.Reset()
k := (pub.N.BitLen() + 7) / 8
if len(msg) > k-2*hash.Size()-2 {
@@ -313,7 +251,7 @@ func EncryptOAEP(hash hash.Hash, rand io.Reader, pub *PublicKey, msg []byte, lab
db[len(db)-len(msg)-1] = 1
copy(db[len(db)-len(msg):], msg)
- _, err = io.ReadFull(rand, seed)
+ _, err = io.ReadFull(random, seed)
if err != nil {
return
}
@@ -405,7 +343,7 @@ func (priv *PrivateKey) Precompute() {
// decrypt performs an RSA decryption, resulting in a plaintext integer. If a
// random source is given, RSA blinding is used.
-func decrypt(rand io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err os.Error) {
+func decrypt(random io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err os.Error) {
// TODO(agl): can we get away with reusing blinds?
if c.Cmp(priv.N) > 0 {
err = DecryptionError{}
@@ -413,16 +351,16 @@ func decrypt(rand io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err os.E
}
var ir *big.Int
- if rand != nil {
+ if random != nil {
// Blinding enabled. Blinding involves multiplying c by r^e.
// Then the decryption operation performs (m^e * r^e)^d mod n
// which equals mr mod n. The factor of r can then be removed
- // by multipling by the multiplicative inverse of r.
+ // by multiplying by the multiplicative inverse of r.
var r *big.Int
for {
- r, err = randomNumber(rand, priv.N)
+ r, err = rand.Int(random, priv.N)
if err != nil {
return
}
@@ -483,7 +421,7 @@ func decrypt(rand io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err os.E
// DecryptOAEP decrypts ciphertext using RSA-OAEP.
// If rand != nil, DecryptOAEP uses RSA blinding to avoid timing side-channel attacks.
-func DecryptOAEP(hash hash.Hash, rand io.Reader, priv *PrivateKey, ciphertext []byte, label []byte) (msg []byte, err os.Error) {
+func DecryptOAEP(hash hash.Hash, random io.Reader, priv *PrivateKey, ciphertext []byte, label []byte) (msg []byte, err os.Error) {
k := (priv.N.BitLen() + 7) / 8
if len(ciphertext) > k ||
k < hash.Size()*2+2 {
@@ -493,7 +431,7 @@ func DecryptOAEP(hash hash.Hash, rand io.Reader, priv *PrivateKey, ciphertext []
c := new(big.Int).SetBytes(ciphertext)
- m, err := decrypt(rand, priv, c)
+ m, err := decrypt(random, priv, c)
if err != nil {
return
}
diff --git a/libgo/go/crypto/subtle/constant_time_test.go b/libgo/go/crypto/subtle/constant_time_test.go
index b28b735..adab8e2 100644
--- a/libgo/go/crypto/subtle/constant_time_test.go
+++ b/libgo/go/crypto/subtle/constant_time_test.go
@@ -14,14 +14,14 @@ type TestConstantTimeCompareStruct struct {
out int
}
-var testConstandTimeCompareData = []TestConstantTimeCompareStruct{
+var testConstantTimeCompareData = []TestConstantTimeCompareStruct{
{[]byte{}, []byte{}, 1},
{[]byte{0x11}, []byte{0x11}, 1},
{[]byte{0x12}, []byte{0x11}, 0},
}
func TestConstantTimeCompare(t *testing.T) {
- for i, test := range testConstandTimeCompareData {
+ for i, test := range testConstantTimeCompareData {
if r := ConstantTimeCompare(test.a, test.b); r != test.out {
t.Errorf("#%d bad result (got %x, want %x)", i, r, test.out)
}
diff --git a/libgo/go/crypto/tls/common.go b/libgo/go/crypto/tls/common.go
index 0b26aae..3efac9c 100644
--- a/libgo/go/crypto/tls/common.go
+++ b/libgo/go/crypto/tls/common.go
@@ -87,7 +87,7 @@ const (
certTypeRSASign = 1 // A certificate containing an RSA key
certTypeDSSSign = 2 // A certificate containing a DSA key
certTypeRSAFixedDH = 3 // A certificate containing a static DH key
- certTypeDSSFixedDH = 4 // A certficiate containing a static DH key
+ certTypeDSSFixedDH = 4 // A certificate containing a static DH key
// Rest of these are reserved by the TLS spec
)
diff --git a/libgo/go/crypto/tls/conn.go b/libgo/go/crypto/tls/conn.go
index 48d3f72..fac65af 100644
--- a/libgo/go/crypto/tls/conn.go
+++ b/libgo/go/crypto/tls/conn.go
@@ -34,7 +34,7 @@ type Conn struct {
cipherSuite uint16
ocspResponse []byte // stapled OCSP response
peerCertificates []*x509.Certificate
- // verifedChains contains the certificate chains that we built, as
+ // verifiedChains contains the certificate chains that we built, as
// opposed to the ones presented by the server.
verifiedChains [][]*x509.Certificate
@@ -237,7 +237,7 @@ func (hc *halfConn) decrypt(b *block) (bool, alert) {
// "Password Interception in a SSL/TLS Channel", Brice
// Canvel et al.
//
- // However, our behaviour matches OpenSSL, so we leak
+ // However, our behavior matches OpenSSL, so we leak
// only as much as they do.
default:
panic("unknown cipher type")
@@ -410,7 +410,7 @@ func (hc *halfConn) freeBlock(b *block) {
// splitBlock splits a block after the first n bytes,
// returning a block with those n bytes and a
-// block with the remaindec. the latter may be nil.
+// block with the remainder. the latter may be nil.
func (hc *halfConn) splitBlock(b *block, n int) (*block, *block) {
if len(b.data) <= n {
return b, nil
@@ -790,10 +790,10 @@ func (c *Conn) VerifyHostname(host string) os.Error {
c.handshakeMutex.Lock()
defer c.handshakeMutex.Unlock()
if !c.isClient {
- return os.ErrorString("VerifyHostname called on TLS server connection")
+ return os.NewError("VerifyHostname called on TLS server connection")
}
if !c.handshakeComplete {
- return os.ErrorString("TLS handshake has not yet been performed")
+ return os.NewError("TLS handshake has not yet been performed")
}
return c.peerCertificates[0].VerifyHostname(host)
}
diff --git a/libgo/go/crypto/tls/generate_cert.go b/libgo/go/crypto/tls/generate_cert.go
index 5b8c700..41206e2 100644
--- a/libgo/go/crypto/tls/generate_cert.go
+++ b/libgo/go/crypto/tls/generate_cert.go
@@ -8,8 +8,10 @@
package main
import (
- "crypto/rsa"
+ "big"
+ "crypto/x509/pkix"
"crypto/rand"
+ "crypto/rsa"
"crypto/x509"
"encoding/pem"
"flag"
@@ -32,8 +34,8 @@ func main() {
now := time.Seconds()
template := x509.Certificate{
- SerialNumber: []byte{0},
- Subject: x509.Name{
+ SerialNumber: new(big.Int).SetInt64(0),
+ Subject: pkix.Name{
CommonName: *hostName,
Organization: []string{"Acme Co"},
},
@@ -59,7 +61,7 @@ func main() {
certOut.Close()
log.Print("written cert.pem\n")
- keyOut, err := os.OpenFile("key.pem", os.O_WRONLY|os.O_CREAT|os.O_TRUNC, 0600)
+ keyOut, err := os.OpenFile("key.pem", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
log.Print("failed to open key.pem for writing:", err)
return
diff --git a/libgo/go/crypto/tls/handshake_client.go b/libgo/go/crypto/tls/handshake_client.go
index c758c96..15604ce 100644
--- a/libgo/go/crypto/tls/handshake_client.go
+++ b/libgo/go/crypto/tls/handshake_client.go
@@ -40,7 +40,7 @@ func (c *Conn) clientHandshake() os.Error {
_, err := io.ReadFull(c.config.rand(), hello.random[4:])
if err != nil {
c.sendAlert(alertInternalError)
- return os.ErrorString("short read from Rand")
+ return os.NewError("short read from Rand")
}
finishedHash.Write(hello.marshal())
@@ -69,7 +69,7 @@ func (c *Conn) clientHandshake() os.Error {
if !hello.nextProtoNeg && serverHello.nextProtoNeg {
c.sendAlert(alertHandshakeFailure)
- return os.ErrorString("server advertised unrequested NPN")
+ return os.NewError("server advertised unrequested NPN")
}
suite, suiteId := mutualCipherSuite(c.config.cipherSuites(), serverHello.cipherSuite)
@@ -92,7 +92,7 @@ func (c *Conn) clientHandshake() os.Error {
cert, err := x509.ParseCertificate(asn1Data)
if err != nil {
c.sendAlert(alertBadCertificate)
- return os.ErrorString("failed to parse certificate from server: " + err.String())
+ return os.NewError("failed to parse certificate from server: " + err.String())
}
certs[i] = cert
}
diff --git a/libgo/go/crypto/tls/handshake_server.go b/libgo/go/crypto/tls/handshake_server.go
index 37c8d15..44a3240 100644
--- a/libgo/go/crypto/tls/handshake_server.go
+++ b/libgo/go/crypto/tls/handshake_server.go
@@ -173,7 +173,7 @@ FindCipherSuite:
cert, err := x509.ParseCertificate(asn1Data)
if err != nil {
c.sendAlert(alertBadCertificate)
- return os.ErrorString("could not parse client's certificate: " + err.String())
+ return os.NewError("could not parse client's certificate: " + err.String())
}
certs[i] = cert
}
@@ -182,7 +182,7 @@ FindCipherSuite:
for i := 1; i < len(certs); i++ {
if err := certs[i-1].CheckSignatureFrom(certs[i]); err != nil {
c.sendAlert(alertBadCertificate)
- return os.ErrorString("could not validate certificate signature: " + err.String())
+ return os.NewError("could not validate certificate signature: " + err.String())
}
}
@@ -209,10 +209,10 @@ FindCipherSuite:
// If we received a client cert in response to our certificate request message,
// the client will send us a certificateVerifyMsg immediately after the
- // clientKeyExchangeMsg. This message is a MD5SHA1 digest of all preceeding
+ // clientKeyExchangeMsg. This message is a MD5SHA1 digest of all preceding
// handshake-layer messages that is signed using the private key corresponding
// to the client's certificate. This allows us to verify that the client is in
- // posession of the private key of the certificate.
+ // possession of the private key of the certificate.
if len(c.peerCertificates) > 0 {
msg, err = c.readHandshake()
if err != nil {
@@ -229,7 +229,7 @@ FindCipherSuite:
err = rsa.VerifyPKCS1v15(pub, crypto.MD5SHA1, digest, certVerify.signature)
if err != nil {
c.sendAlert(alertBadCertificate)
- return os.ErrorString("could not validate signature of connection nonces: " + err.String())
+ return os.NewError("could not validate signature of connection nonces: " + err.String())
}
finishedHash.Write(certVerify.marshal())
diff --git a/libgo/go/crypto/tls/handshake_server_test.go b/libgo/go/crypto/tls/handshake_server_test.go
index 5a1e754..b77646e 100644
--- a/libgo/go/crypto/tls/handshake_server_test.go
+++ b/libgo/go/crypto/tls/handshake_server_test.go
@@ -106,7 +106,6 @@ func TestClose(t *testing.T) {
}
}
-
func testServerScript(t *testing.T, name string, serverScript [][]byte, config *Config) {
c, s := net.Pipe()
srv := Server(s, config)
diff --git a/libgo/go/crypto/tls/key_agreement.go b/libgo/go/crypto/tls/key_agreement.go
index 8edbb11..a40d18f 100644
--- a/libgo/go/crypto/tls/key_agreement.go
+++ b/libgo/go/crypto/tls/key_agreement.go
@@ -32,11 +32,11 @@ func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, ckx *clientKe
}
if len(ckx.ciphertext) < 2 {
- return nil, os.ErrorString("bad ClientKeyExchange")
+ return nil, os.NewError("bad ClientKeyExchange")
}
ciphertextLen := int(ckx.ciphertext[0])<<8 | int(ckx.ciphertext[1])
if ciphertextLen != len(ckx.ciphertext)-2 {
- return nil, os.ErrorString("bad ClientKeyExchange")
+ return nil, os.NewError("bad ClientKeyExchange")
}
ciphertext := ckx.ciphertext[2:]
@@ -54,7 +54,7 @@ func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, ckx *clientKe
}
func (ka rsaKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) os.Error {
- return os.ErrorString("unexpected ServerKeyExchange")
+ return os.NewError("unexpected ServerKeyExchange")
}
func (ka rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, os.Error) {
@@ -78,7 +78,6 @@ func (ka rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello
return preMasterSecret, ckx, nil
}
-
// md5SHA1Hash implements TLS 1.0's hybrid hash function which consists of the
// concatenation of an MD5 and SHA1 hash.
func md5SHA1Hash(slices ...[]byte) []byte {
@@ -146,7 +145,7 @@ Curve:
md5sha1 := md5SHA1Hash(clientHello.random, hello.random, serverECDHParams)
sig, err := rsa.SignPKCS1v15(config.rand(), config.Certificates[0].PrivateKey, crypto.MD5SHA1, md5sha1)
if err != nil {
- return nil, os.ErrorString("failed to sign ECDHE parameters: " + err.String())
+ return nil, os.NewError("failed to sign ECDHE parameters: " + err.String())
}
skx := new(serverKeyExchangeMsg)
@@ -162,11 +161,11 @@ Curve:
func (ka *ecdheRSAKeyAgreement) processClientKeyExchange(config *Config, ckx *clientKeyExchangeMsg) ([]byte, os.Error) {
if len(ckx.ciphertext) == 0 || int(ckx.ciphertext[0]) != len(ckx.ciphertext)-1 {
- return nil, os.ErrorString("bad ClientKeyExchange")
+ return nil, os.NewError("bad ClientKeyExchange")
}
x, y := ka.curve.Unmarshal(ckx.ciphertext[1:])
if x == nil {
- return nil, os.ErrorString("bad ClientKeyExchange")
+ return nil, os.NewError("bad ClientKeyExchange")
}
x, _ = ka.curve.ScalarMult(x, y, ka.privateKey)
preMasterSecret := make([]byte, (ka.curve.BitSize+7)>>3)
@@ -176,12 +175,14 @@ func (ka *ecdheRSAKeyAgreement) processClientKeyExchange(config *Config, ckx *cl
return preMasterSecret, nil
}
+var errServerKeyExchange = os.NewError("invalid ServerKeyExchange")
+
func (ka *ecdheRSAKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) os.Error {
if len(skx.key) < 4 {
- goto Error
+ return errServerKeyExchange
}
if skx.key[0] != 3 { // named curve
- return os.ErrorString("server selected unsupported curve")
+ return os.NewError("server selected unsupported curve")
}
curveid := uint16(skx.key[1])<<8 | uint16(skx.key[2])
@@ -193,39 +194,36 @@ func (ka *ecdheRSAKeyAgreement) processServerKeyExchange(config *Config, clientH
case curveP521:
ka.curve = elliptic.P521()
default:
- return os.ErrorString("server selected unsupported curve")
+ return os.NewError("server selected unsupported curve")
}
publicLen := int(skx.key[3])
if publicLen+4 > len(skx.key) {
- goto Error
+ return errServerKeyExchange
}
ka.x, ka.y = ka.curve.Unmarshal(skx.key[4 : 4+publicLen])
if ka.x == nil {
- goto Error
+ return errServerKeyExchange
}
serverECDHParams := skx.key[:4+publicLen]
sig := skx.key[4+publicLen:]
if len(sig) < 2 {
- goto Error
+ return errServerKeyExchange
}
sigLen := int(sig[0])<<8 | int(sig[1])
if sigLen+2 != len(sig) {
- goto Error
+ return errServerKeyExchange
}
sig = sig[2:]
md5sha1 := md5SHA1Hash(clientHello.random, serverHello.random, serverECDHParams)
return rsa.VerifyPKCS1v15(cert.PublicKey.(*rsa.PublicKey), crypto.MD5SHA1, md5sha1, sig)
-
-Error:
- return os.ErrorString("invalid ServerKeyExchange")
}
func (ka *ecdheRSAKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, os.Error) {
if ka.curve == nil {
- return nil, nil, os.ErrorString("missing ServerKeyExchange message")
+ return nil, nil, os.NewError("missing ServerKeyExchange message")
}
priv, mx, my, err := ka.curve.GenerateKey(config.rand())
if err != nil {
@@ -236,12 +234,12 @@ func (ka *ecdheRSAKeyAgreement) generateClientKeyExchange(config *Config, client
xBytes := x.Bytes()
copy(preMasterSecret[len(preMasterSecret)-len(xBytes):], xBytes)
- serialised := ka.curve.Marshal(mx, my)
+ serialized := ka.curve.Marshal(mx, my)
ckx := new(clientKeyExchangeMsg)
- ckx.ciphertext = make([]byte, 1+len(serialised))
- ckx.ciphertext[0] = byte(len(serialised))
- copy(ckx.ciphertext[1:], serialised)
+ ckx.ciphertext = make([]byte, 1+len(serialized))
+ ckx.ciphertext[0] = byte(len(serialized))
+ copy(ckx.ciphertext[1:], serialized)
return preMasterSecret, ckx, nil
}
diff --git a/libgo/go/crypto/tls/tls.go b/libgo/go/crypto/tls/tls.go
index 7d0bb9f..4f0859f 100644
--- a/libgo/go/crypto/tls/tls.go
+++ b/libgo/go/crypto/tls/tls.go
@@ -147,19 +147,19 @@ func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (cert Certificate, err os.Err
}
if len(cert.Certificate) == 0 {
- err = os.ErrorString("crypto/tls: failed to parse certificate PEM data")
+ err = os.NewError("crypto/tls: failed to parse certificate PEM data")
return
}
keyDERBlock, _ := pem.Decode(keyPEMBlock)
if keyDERBlock == nil {
- err = os.ErrorString("crypto/tls: failed to parse key PEM data")
+ err = os.NewError("crypto/tls: failed to parse key PEM data")
return
}
key, err := x509.ParsePKCS1PrivateKey(keyDERBlock.Bytes)
if err != nil {
- err = os.ErrorString("crypto/tls: failed to parse key")
+ err = os.NewError("crypto/tls: failed to parse key: " + err.String())
return
}
@@ -173,7 +173,7 @@ func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (cert Certificate, err os.Err
}
if x509Cert.PublicKeyAlgorithm != x509.RSA || x509Cert.PublicKey.(*rsa.PublicKey).N.Cmp(key.PublicKey.N) != 0 {
- err = os.ErrorString("crypto/tls: private key does not match public key")
+ err = os.NewError("crypto/tls: private key does not match public key")
return
}
diff --git a/libgo/go/crypto/twofish/twofish.go b/libgo/go/crypto/twofish/twofish.go
index 9303f03..2e537c6 100644
--- a/libgo/go/crypto/twofish/twofish.go
+++ b/libgo/go/crypto/twofish/twofish.go
@@ -116,7 +116,7 @@ func (c *Cipher) Reset() {
c.k[i] = 0
}
for i := range c.s {
- for j := 0; j < 265; j++ {
+ for j := 0; j < 256; j++ {
c.s[i][j] = 0
}
}
@@ -269,7 +269,7 @@ func h(in, key []byte, offset int) uint32 {
// Encrypt encrypts a 16-byte block from src to dst, which may overlap.
// Note that for amounts of data larger than a block,
// it is not safe to just call Encrypt on successive blocks;
-// instead, use an encryption mode like CBC (see crypto/block/cbc.go).
+// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go).
func (c *Cipher) Encrypt(dst, src []byte) {
S1 := c.s[0]
S2 := c.s[1]
diff --git a/libgo/go/crypto/x509/cert_pool.go b/libgo/go/crypto/x509/cert_pool.go
index c295fd9..16cd92e 100644
--- a/libgo/go/crypto/x509/cert_pool.go
+++ b/libgo/go/crypto/x509/cert_pool.go
@@ -5,6 +5,7 @@
package x509
import (
+ "crypto/x509/pkix"
"encoding/pem"
"strings"
)
@@ -25,7 +26,7 @@ func NewCertPool() *CertPool {
}
}
-func nameToKey(name *Name) string {
+func nameToKey(name *pkix.Name) string {
return strings.Join(name.Country, ",") + "/" + strings.Join(name.Organization, ",") + "/" + strings.Join(name.OrganizationalUnit, ",") + "/" + name.CommonName
}
diff --git a/libgo/go/crypto/x509/pkix/pkix.go b/libgo/go/crypto/x509/pkix/pkix.go
new file mode 100644
index 0000000..266fd55
--- /dev/null
+++ b/libgo/go/crypto/x509/pkix/pkix.go
@@ -0,0 +1,167 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package pkix contains shared, low level structures used for ASN.1 parsing
+// and serialization of X.509 certificates, CRL and OCSP.
+package pkix
+
+import (
+ "asn1"
+ "big"
+ "time"
+)
+
+// AlgorithmIdentifier represents the ASN.1 structure of the same name. See RFC
+// 5280, section 4.1.1.2.
+type AlgorithmIdentifier struct {
+ Algorithm asn1.ObjectIdentifier
+ Parameters asn1.RawValue `asn1:"optional"`
+}
+
+type RDNSequence []RelativeDistinguishedNameSET
+
+type RelativeDistinguishedNameSET []AttributeTypeAndValue
+
+type AttributeTypeAndValue struct {
+ Type asn1.ObjectIdentifier
+ Value interface{}
+}
+
+// Extension represents the ASN.1 structure of the same name. See RFC
+// 5280, section 4.2.
+type Extension struct {
+ Id asn1.ObjectIdentifier
+ Critical bool `asn1:"optional"`
+ Value []byte
+}
+
+// Name represents an X.509 distinguished name. This only includes the common
+// elements of a DN. Additional elements in the name are ignored.
+type Name struct {
+ Country, Organization, OrganizationalUnit []string
+ Locality, Province []string
+ StreetAddress, PostalCode []string
+ SerialNumber, CommonName string
+}
+
+func (n *Name) FillFromRDNSequence(rdns *RDNSequence) {
+ for _, rdn := range *rdns {
+ if len(rdn) == 0 {
+ continue
+ }
+ atv := rdn[0]
+ value, ok := atv.Value.(string)
+ if !ok {
+ continue
+ }
+
+ t := atv.Type
+ if len(t) == 4 && t[0] == 2 && t[1] == 5 && t[2] == 4 {
+ switch t[3] {
+ case 3:
+ n.CommonName = value
+ case 5:
+ n.SerialNumber = value
+ case 6:
+ n.Country = append(n.Country, value)
+ case 7:
+ n.Locality = append(n.Locality, value)
+ case 8:
+ n.Province = append(n.Province, value)
+ case 9:
+ n.StreetAddress = append(n.StreetAddress, value)
+ case 10:
+ n.Organization = append(n.Organization, value)
+ case 11:
+ n.OrganizationalUnit = append(n.OrganizationalUnit, value)
+ case 17:
+ n.PostalCode = append(n.PostalCode, value)
+ }
+ }
+ }
+}
+
+var (
+ oidCountry = []int{2, 5, 4, 6}
+ oidOrganization = []int{2, 5, 4, 10}
+ oidOrganizationalUnit = []int{2, 5, 4, 11}
+ oidCommonName = []int{2, 5, 4, 3}
+ oidSerialNumber = []int{2, 5, 4, 5}
+ oidLocality = []int{2, 5, 4, 7}
+ oidProvince = []int{2, 5, 4, 8}
+ oidStreetAddress = []int{2, 5, 4, 9}
+ oidPostalCode = []int{2, 5, 4, 17}
+)
+
+// appendRDNs appends a relativeDistinguishedNameSET to the given RDNSequence
+// and returns the new value. The relativeDistinguishedNameSET contains an
+// attributeTypeAndValue for each of the given values. See RFC 5280, A.1, and
+// search for AttributeTypeAndValue.
+func appendRDNs(in RDNSequence, values []string, oid asn1.ObjectIdentifier) RDNSequence {
+ if len(values) == 0 {
+ return in
+ }
+
+ s := make([]AttributeTypeAndValue, len(values))
+ for i, value := range values {
+ s[i].Type = oid
+ s[i].Value = value
+ }
+
+ return append(in, s)
+}
+
+func (n Name) ToRDNSequence() (ret RDNSequence) {
+ ret = appendRDNs(ret, n.Country, oidCountry)
+ ret = appendRDNs(ret, n.Organization, oidOrganization)
+ ret = appendRDNs(ret, n.OrganizationalUnit, oidOrganizationalUnit)
+ ret = appendRDNs(ret, n.Locality, oidLocality)
+ ret = appendRDNs(ret, n.Province, oidProvince)
+ ret = appendRDNs(ret, n.StreetAddress, oidStreetAddress)
+ ret = appendRDNs(ret, n.PostalCode, oidPostalCode)
+ if len(n.CommonName) > 0 {
+ ret = appendRDNs(ret, []string{n.CommonName}, oidCommonName)
+ }
+ if len(n.SerialNumber) > 0 {
+ ret = appendRDNs(ret, []string{n.SerialNumber}, oidSerialNumber)
+ }
+
+ return ret
+}
+
+// CertificateList represents the ASN.1 structure of the same name. See RFC
+// 5280, section 5.1. Use Certificate.CheckCRLSignature to verify the
+// signature.
+type CertificateList struct {
+ TBSCertList TBSCertificateList
+ SignatureAlgorithm AlgorithmIdentifier
+ SignatureValue asn1.BitString
+}
+
+// HasExpired returns true iff currentTimeSeconds is past the expiry time of
+// certList.
+func (certList *CertificateList) HasExpired(currentTimeSeconds int64) bool {
+ return certList.TBSCertList.NextUpdate.Seconds() <= currentTimeSeconds
+}
+
+// TBSCertificateList represents the ASN.1 structure of the same name. See RFC
+// 5280, section 5.1.
+type TBSCertificateList struct {
+ Raw asn1.RawContent
+ Version int `asn1:"optional,default:2"`
+ Signature AlgorithmIdentifier
+ Issuer RDNSequence
+ ThisUpdate *time.Time
+ NextUpdate *time.Time
+ RevokedCertificates []RevokedCertificate `asn1:"optional"`
+ Extensions []Extension `asn1:"tag:0,optional,explicit"`
+}
+
+// RevokedCertificate represents the ASN.1 structure of the same name. See RFC
+// 5280, section 5.1.
+type RevokedCertificate struct {
+ SerialNumber *big.Int
+ RevocationTime *time.Time
+ Extensions []Extension `asn1:"optional"`
+}
diff --git a/libgo/go/crypto/x509/verify.go b/libgo/go/crypto/x509/verify.go
index 9145880..4c0fecc 100644
--- a/libgo/go/crypto/x509/verify.go
+++ b/libgo/go/crypto/x509/verify.go
@@ -62,7 +62,6 @@ func (h HostnameError) String() string {
return "certificate is valid for " + valid + ", not " + h.Host
}
-
// UnknownAuthorityError results when the certificate issuer is unknown
type UnknownAuthorityError struct {
cert *Certificate
@@ -171,8 +170,14 @@ func (c *Certificate) buildChains(cache map[int][][]*Certificate, currentChain [
chains = append(chains, appendToFreshChain(currentChain, root))
}
+nextIntermediate:
for _, intermediateNum := range opts.Intermediates.findVerifiedParents(c) {
intermediate := opts.Intermediates.certs[intermediateNum]
+ for _, cert := range currentChain {
+ if cert == intermediate {
+ continue nextIntermediate
+ }
+ }
err = intermediate.isValid(intermediateCertificate, opts)
if err != nil {
continue
@@ -202,8 +207,8 @@ func matchHostnames(pattern, host string) bool {
return false
}
- patternParts := strings.Split(pattern, ".", -1)
- hostParts := strings.Split(host, ".", -1)
+ patternParts := strings.Split(pattern, ".")
+ hostParts := strings.Split(host, ".")
if len(patternParts) != len(hostParts) {
return false
diff --git a/libgo/go/crypto/x509/verify_test.go b/libgo/go/crypto/x509/verify_test.go
index 6a103dc..111f60e 100644
--- a/libgo/go/crypto/x509/verify_test.go
+++ b/libgo/go/crypto/x509/verify_test.go
@@ -72,23 +72,24 @@ var verifyTests = []verifyTest{
},
},
{
- leaf: googleLeaf,
- intermediates: []string{verisignRoot, thawteIntermediate},
- roots: []string{verisignRoot},
+ leaf: dnssecExpLeaf,
+ intermediates: []string{startComIntermediate},
+ roots: []string{startComRoot},
currentTime: 1302726541,
expectedChains: [][]string{
- []string{"Google", "Thawte", "VeriSign"},
+ []string{"dnssec-exp", "StartCom Class 1", "StartCom Certification Authority"},
},
},
{
leaf: dnssecExpLeaf,
- intermediates: []string{startComIntermediate},
+ intermediates: []string{startComIntermediate, startComRoot},
roots: []string{startComRoot},
currentTime: 1302726541,
expectedChains: [][]string{
[]string{"dnssec-exp", "StartCom Class 1", "StartCom Certification Authority"},
+ []string{"dnssec-exp", "StartCom Class 1", "StartCom Certification Authority", "StartCom Certification Authority"},
},
},
}
@@ -120,7 +121,7 @@ func expectAuthorityUnknown(t *testing.T, i int, err os.Error) (ok bool) {
func certificateFromPEM(pemBytes string) (*Certificate, os.Error) {
block, _ := pem.Decode([]byte(pemBytes))
if block == nil {
- return nil, os.ErrorString("failed to decode PEM")
+ return nil, os.NewError("failed to decode PEM")
}
return ParseCertificate(block.Bytes)
}
diff --git a/libgo/go/crypto/x509/x509.go b/libgo/go/crypto/x509/x509.go
index d0c5a26..8fda471 100644
--- a/libgo/go/crypto/x509/x509.go
+++ b/libgo/go/crypto/x509/x509.go
@@ -9,11 +9,12 @@ import (
"asn1"
"big"
"bytes"
- "container/vector"
"crypto"
+ "crypto/dsa"
"crypto/rsa"
"crypto/sha1"
- "hash"
+ "crypto/x509/pkix"
+ "encoding/pem"
"io"
"os"
"time"
@@ -22,30 +23,25 @@ import (
// pkcs1PrivateKey is a structure which mirrors the PKCS#1 ASN.1 for an RSA private key.
type pkcs1PrivateKey struct {
Version int
- N asn1.RawValue
+ N *big.Int
E int
- D asn1.RawValue
- P asn1.RawValue
- Q asn1.RawValue
+ D *big.Int
+ P *big.Int
+ Q *big.Int
// We ignore these values, if present, because rsa will calculate them.
- Dp asn1.RawValue "optional"
- Dq asn1.RawValue "optional"
- Qinv asn1.RawValue "optional"
+ Dp *big.Int `asn1:"optional"`
+ Dq *big.Int `asn1:"optional"`
+ Qinv *big.Int `asn1:"optional"`
- AdditionalPrimes []pkcs1AddtionalRSAPrime "optional"
+ AdditionalPrimes []pkcs1AdditionalRSAPrime `asn1:"optional"`
}
-type pkcs1AddtionalRSAPrime struct {
- Prime asn1.RawValue
+type pkcs1AdditionalRSAPrime struct {
+ Prime *big.Int
// We ignore these values because rsa will calculate them.
- Exp asn1.RawValue
- Coeff asn1.RawValue
-}
-
-// rawValueIsInteger returns true iff the given ASN.1 RawValue is an INTEGER type.
-func rawValueIsInteger(raw *asn1.RawValue) bool {
- return raw.Class == 0 && raw.Tag == 2 && raw.IsCompound == false
+ Exp *big.Int
+ Coeff *big.Int
}
// ParsePKCS1PrivateKey returns an RSA private key from its ASN.1 PKCS#1 DER encoded form.
@@ -61,32 +57,28 @@ func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err os.Error) {
}
if priv.Version > 1 {
- return nil, os.ErrorString("x509: unsupported private key version")
+ return nil, os.NewError("x509: unsupported private key version")
}
- if !rawValueIsInteger(&priv.N) ||
- !rawValueIsInteger(&priv.D) ||
- !rawValueIsInteger(&priv.P) ||
- !rawValueIsInteger(&priv.Q) {
- err = asn1.StructuralError{"tags don't match"}
- return
+ if priv.N.Sign() <= 0 || priv.D.Sign() <= 0 || priv.P.Sign() <= 0 || priv.Q.Sign() <= 0 {
+ return nil, os.NewError("private key contains zero or negative value")
}
key = new(rsa.PrivateKey)
key.PublicKey = rsa.PublicKey{
E: priv.E,
- N: new(big.Int).SetBytes(priv.N.Bytes),
+ N: priv.N,
}
- key.D = new(big.Int).SetBytes(priv.D.Bytes)
+ key.D = priv.D
key.Primes = make([]*big.Int, 2+len(priv.AdditionalPrimes))
- key.Primes[0] = new(big.Int).SetBytes(priv.P.Bytes)
- key.Primes[1] = new(big.Int).SetBytes(priv.Q.Bytes)
+ key.Primes[0] = priv.P
+ key.Primes[1] = priv.Q
for i, a := range priv.AdditionalPrimes {
- if !rawValueIsInteger(&a.Prime) {
- return nil, asn1.StructuralError{"tags don't match"}
+ if a.Prime.Sign() <= 0 {
+ return nil, os.NewError("private key contains zero or negative prime")
}
- key.Primes[i+2] = new(big.Int).SetBytes(a.Prime.Bytes)
+ key.Primes[i+2] = a.Prime
// We ignore the other two values because rsa will calculate
// them as needed.
}
@@ -100,19 +92,6 @@ func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err os.Error) {
return
}
-// rawValueForBig returns an asn1.RawValue which represents the given integer.
-func rawValueForBig(n *big.Int) asn1.RawValue {
- b := n.Bytes()
- if n.Sign() >= 0 && len(b) > 0 && b[0]&0x80 != 0 {
- // This positive number would be interpreted as a negative
- // number in ASN.1 because the MSB is set.
- padded := make([]byte, len(b)+1)
- copy(padded[1:], b)
- b = padded
- }
- return asn1.RawValue{Tag: 2, Bytes: b}
-}
-
// MarshalPKCS1PrivateKey converts a private key to ASN.1 DER encoded form.
func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte {
key.Precompute()
@@ -124,21 +103,21 @@ func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte {
priv := pkcs1PrivateKey{
Version: version,
- N: rawValueForBig(key.N),
+ N: key.N,
E: key.PublicKey.E,
- D: rawValueForBig(key.D),
- P: rawValueForBig(key.Primes[0]),
- Q: rawValueForBig(key.Primes[1]),
- Dp: rawValueForBig(key.Precomputed.Dp),
- Dq: rawValueForBig(key.Precomputed.Dq),
- Qinv: rawValueForBig(key.Precomputed.Qinv),
+ D: key.D,
+ P: key.Primes[0],
+ Q: key.Primes[1],
+ Dp: key.Precomputed.Dp,
+ Dq: key.Precomputed.Dq,
+ Qinv: key.Precomputed.Qinv,
}
- priv.AdditionalPrimes = make([]pkcs1AddtionalRSAPrime, len(key.Precomputed.CRTValues))
+ priv.AdditionalPrimes = make([]pkcs1AdditionalRSAPrime, len(key.Precomputed.CRTValues))
for i, values := range key.Precomputed.CRTValues {
- priv.AdditionalPrimes[i].Prime = rawValueForBig(key.Primes[2+i])
- priv.AdditionalPrimes[i].Exp = rawValueForBig(values.Exp)
- priv.AdditionalPrimes[i].Coeff = rawValueForBig(values.Coeff)
+ priv.AdditionalPrimes[i].Prime = key.Primes[2+i]
+ priv.AdditionalPrimes[i].Exp = values.Exp
+ priv.AdditionalPrimes[i].Coeff = values.Coeff
}
b, _ := asn1.Marshal(priv)
@@ -150,35 +129,30 @@ func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte {
type certificate struct {
Raw asn1.RawContent
TBSCertificate tbsCertificate
- SignatureAlgorithm algorithmIdentifier
+ SignatureAlgorithm pkix.AlgorithmIdentifier
SignatureValue asn1.BitString
}
type tbsCertificate struct {
Raw asn1.RawContent
- Version int "optional,explicit,default:1,tag:0"
- SerialNumber asn1.RawValue
- SignatureAlgorithm algorithmIdentifier
- Issuer rdnSequence
+ Version int `asn1:"optional,explicit,default:1,tag:0"`
+ SerialNumber *big.Int
+ SignatureAlgorithm pkix.AlgorithmIdentifier
+ Issuer pkix.RDNSequence
Validity validity
- Subject rdnSequence
+ Subject pkix.RDNSequence
PublicKey publicKeyInfo
- UniqueId asn1.BitString "optional,tag:1"
- SubjectUniqueId asn1.BitString "optional,tag:2"
- Extensions []extension "optional,explicit,tag:3"
+ UniqueId asn1.BitString `asn1:"optional,tag:1"`
+ SubjectUniqueId asn1.BitString `asn1:"optional,tag:2"`
+ Extensions []pkix.Extension `asn1:"optional,explicit,tag:3"`
}
-type algorithmIdentifier struct {
- Algorithm asn1.ObjectIdentifier
+type dsaAlgorithmParameters struct {
+ P, Q, G *big.Int
}
-type rdnSequence []relativeDistinguishedNameSET
-
-type relativeDistinguishedNameSET []attributeTypeAndValue
-
-type attributeTypeAndValue struct {
- Type asn1.ObjectIdentifier
- Value interface{}
+type dsaSignature struct {
+ R, S *big.Int
}
type validity struct {
@@ -187,19 +161,13 @@ type validity struct {
type publicKeyInfo struct {
Raw asn1.RawContent
- Algorithm algorithmIdentifier
+ Algorithm pkix.AlgorithmIdentifier
PublicKey asn1.BitString
}
-type extension struct {
- Id asn1.ObjectIdentifier
- Critical bool "optional"
- Value []byte
-}
-
// RFC 5280, 4.2.1.1
type authKeyId struct {
- Id []byte "optional,tag:0"
+ Id []byte `asn1:"optional,tag:0"`
}
type SignatureAlgorithm int
@@ -212,6 +180,8 @@ const (
SHA256WithRSA
SHA384WithRSA
SHA512WithRSA
+ DSAWithSHA1
+ DSAWithSHA256
)
type PublicKeyAlgorithm int
@@ -219,133 +189,96 @@ type PublicKeyAlgorithm int
const (
UnknownPublicKeyAlgorithm PublicKeyAlgorithm = iota
RSA
+ DSA
)
-// Name represents an X.509 distinguished name. This only includes the common
-// elements of a DN. Additional elements in the name are ignored.
-type Name struct {
- Country, Organization, OrganizationalUnit []string
- Locality, Province []string
- StreetAddress, PostalCode []string
- SerialNumber, CommonName string
-}
-
-func (n *Name) fillFromRDNSequence(rdns *rdnSequence) {
- for _, rdn := range *rdns {
- if len(rdn) == 0 {
- continue
- }
- atv := rdn[0]
- value, ok := atv.Value.(string)
- if !ok {
- continue
- }
-
- t := atv.Type
- if len(t) == 4 && t[0] == 2 && t[1] == 5 && t[2] == 4 {
- switch t[3] {
- case 3:
- n.CommonName = value
- case 5:
- n.SerialNumber = value
- case 6:
- n.Country = append(n.Country, value)
- case 7:
- n.Locality = append(n.Locality, value)
- case 8:
- n.Province = append(n.Province, value)
- case 9:
- n.StreetAddress = append(n.StreetAddress, value)
- case 10:
- n.Organization = append(n.Organization, value)
- case 11:
- n.OrganizationalUnit = append(n.OrganizationalUnit, value)
- case 17:
- n.PostalCode = append(n.PostalCode, value)
- }
- }
- }
-}
-
+// OIDs for signature algorithms
+//
+// pkcs-1 OBJECT IDENTIFIER ::= {
+// iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 }
+//
+//
+// RFC 3279 2.2.1 RSA Signature Algorithms
+//
+// md2WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 2 }
+//
+// md5WithRSAEncryption OBJECT IDENTIFER ::= { pkcs-1 4 }
+//
+// sha-1WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 5 }
+//
+// dsaWithSha1 OBJECT IDENTIFIER ::= {
+// iso(1) member-body(2) us(840) x9-57(10040) x9cm(4) 3 }
+//
+//
+// RFC 4055 5 PKCS #1 Version 1.5
+//
+// sha256WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 11 }
+//
+// sha384WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 12 }
+//
+// sha512WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 13 }
+//
+//
+// RFC 5758 3.1 DSA Signature Algorithms
+//
+// dsaWithSha356 OBJECT IDENTIFER ::= {
+// joint-iso-ccitt(2) country(16) us(840) organization(1) gov(101)
+// algorithms(4) id-dsa-with-sha2(3) 2}
+//
var (
- oidCountry = []int{2, 5, 4, 6}
- oidOrganization = []int{2, 5, 4, 10}
- oidOrganizationalUnit = []int{2, 5, 4, 11}
- oidCommonName = []int{2, 5, 4, 3}
- oidSerialNumber = []int{2, 5, 4, 5}
- oidLocatity = []int{2, 5, 4, 7}
- oidProvince = []int{2, 5, 4, 8}
- oidStreetAddress = []int{2, 5, 4, 9}
- oidPostalCode = []int{2, 5, 4, 17}
+ oidSignatureMD2WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 2}
+ oidSignatureMD5WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 4}
+ oidSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5}
+ oidSignatureSHA256WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11}
+ oidSignatureSHA384WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12}
+ oidSignatureSHA512WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13}
+ oidSignatureDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 3}
+ oidSignatureDSAWithSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 4, 3, 2}
)
-// appendRDNs appends a relativeDistinguishedNameSET to the given rdnSequence
-// and returns the new value. The relativeDistinguishedNameSET contains an
-// attributeTypeAndValue for each of the given values. See RFC 5280, A.1, and
-// search for AttributeTypeAndValue.
-func appendRDNs(in rdnSequence, values []string, oid asn1.ObjectIdentifier) rdnSequence {
- if len(values) == 0 {
- return in
- }
-
- s := make([]attributeTypeAndValue, len(values))
- for i, value := range values {
- s[i].Type = oid
- s[i].Value = value
- }
-
- return append(in, s)
-}
-
-func (n Name) toRDNSequence() (ret rdnSequence) {
- ret = appendRDNs(ret, n.Country, oidCountry)
- ret = appendRDNs(ret, n.Organization, oidOrganization)
- ret = appendRDNs(ret, n.OrganizationalUnit, oidOrganizationalUnit)
- ret = appendRDNs(ret, n.Locality, oidLocatity)
- ret = appendRDNs(ret, n.Province, oidProvince)
- ret = appendRDNs(ret, n.StreetAddress, oidStreetAddress)
- ret = appendRDNs(ret, n.PostalCode, oidPostalCode)
- if len(n.CommonName) > 0 {
- ret = appendRDNs(ret, []string{n.CommonName}, oidCommonName)
- }
- if len(n.SerialNumber) > 0 {
- ret = appendRDNs(ret, []string{n.SerialNumber}, oidSerialNumber)
- }
-
- return ret
-}
-
-func getSignatureAlgorithmFromOID(oid []int) SignatureAlgorithm {
- if len(oid) == 7 && oid[0] == 1 && oid[1] == 2 && oid[2] == 840 &&
- oid[3] == 113549 && oid[4] == 1 && oid[5] == 1 {
- switch oid[6] {
- case 2:
- return MD2WithRSA
- case 4:
- return MD5WithRSA
- case 5:
- return SHA1WithRSA
- case 11:
- return SHA256WithRSA
- case 12:
- return SHA384WithRSA
- case 13:
- return SHA512WithRSA
- }
+func getSignatureAlgorithmFromOID(oid asn1.ObjectIdentifier) SignatureAlgorithm {
+ switch {
+ case oid.Equal(oidSignatureMD2WithRSA):
+ return MD2WithRSA
+ case oid.Equal(oidSignatureMD5WithRSA):
+ return MD5WithRSA
+ case oid.Equal(oidSignatureSHA1WithRSA):
+ return SHA1WithRSA
+ case oid.Equal(oidSignatureSHA256WithRSA):
+ return SHA256WithRSA
+ case oid.Equal(oidSignatureSHA384WithRSA):
+ return SHA384WithRSA
+ case oid.Equal(oidSignatureSHA512WithRSA):
+ return SHA512WithRSA
+ case oid.Equal(oidSignatureDSAWithSHA1):
+ return DSAWithSHA1
+ case oid.Equal(oidSignatureDSAWithSHA256):
+ return DSAWithSHA256
}
-
return UnknownSignatureAlgorithm
}
-func getPublicKeyAlgorithmFromOID(oid []int) PublicKeyAlgorithm {
- if len(oid) == 7 && oid[0] == 1 && oid[1] == 2 && oid[2] == 840 &&
- oid[3] == 113549 && oid[4] == 1 && oid[5] == 1 {
- switch oid[6] {
- case 1:
- return RSA
- }
- }
+// RFC 3279, 2.3 Public Key Algorithms
+//
+// pkcs-1 OBJECT IDENTIFIER ::== { iso(1) member-body(2) us(840)
+// rsadsi(113549) pkcs(1) 1 }
+//
+// rsaEncryption OBJECT IDENTIFIER ::== { pkcs1-1 1 }
+//
+// id-dsa OBJECT IDENTIFIER ::== { iso(1) member-body(2) us(840)
+// x9-57(10040) x9cm(4) 1 }
+var (
+ oidPublicKeyRsa = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
+ oidPublicKeyDsa = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 1}
+)
+func getPublicKeyAlgorithmFromOID(oid asn1.ObjectIdentifier) PublicKeyAlgorithm {
+ switch {
+ case oid.Equal(oidPublicKeyRsa):
+ return RSA
+ case oid.Equal(oidPublicKeyDsa):
+ return DSA
+ }
return UnknownPublicKeyAlgorithm
}
@@ -414,9 +347,9 @@ type Certificate struct {
PublicKey interface{}
Version int
- SerialNumber []byte
- Issuer Name
- Subject Name
+ SerialNumber *big.Int
+ Issuer pkix.Name
+ Subject pkix.Name
NotBefore, NotAfter *time.Time // Validity bounds.
KeyUsage KeyUsage
@@ -485,26 +418,58 @@ func (c *Certificate) CheckSignatureFrom(parent *Certificate) (err os.Error) {
// TODO(agl): don't ignore the path length constraint.
- var h hash.Hash
+ return parent.CheckSignature(c.SignatureAlgorithm, c.RawTBSCertificate, c.Signature)
+}
+
+// CheckSignature verifies that signature is a valid signature over signed from
+// c's public key.
+func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature []byte) (err os.Error) {
var hashType crypto.Hash
- switch c.SignatureAlgorithm {
- case SHA1WithRSA:
- h = sha1.New()
+ switch algo {
+ case SHA1WithRSA, DSAWithSHA1:
hashType = crypto.SHA1
+ case SHA256WithRSA, DSAWithSHA256:
+ hashType = crypto.SHA256
+ case SHA384WithRSA:
+ hashType = crypto.SHA384
+ case SHA512WithRSA:
+ hashType = crypto.SHA512
default:
return UnsupportedAlgorithmError{}
}
- pub, ok := parent.PublicKey.(*rsa.PublicKey)
- if !ok {
+ h := hashType.New()
+ if h == nil {
return UnsupportedAlgorithmError{}
}
- h.Write(c.RawTBSCertificate)
+ h.Write(signed)
digest := h.Sum()
- return rsa.VerifyPKCS1v15(pub, hashType, digest, c.Signature)
+ switch pub := c.PublicKey.(type) {
+ case *rsa.PublicKey:
+ return rsa.VerifyPKCS1v15(pub, hashType, digest, signature)
+ case *dsa.PublicKey:
+ dsaSig := new(dsaSignature)
+ if _, err := asn1.Unmarshal(signature, dsaSig); err != nil {
+ return err
+ }
+ if dsaSig.R.Sign() <= 0 || dsaSig.S.Sign() <= 0 {
+ return os.NewError("DSA signature contained zero or negative values")
+ }
+ if !dsa.Verify(pub, digest, dsaSig.R, dsaSig.S) {
+ return os.NewError("DSA verification failure")
+ }
+ return
+ }
+ return UnsupportedAlgorithmError{}
+}
+
+// CheckCRLSignature checks that the signature in crl is from c.
+func (c *Certificate) CheckCRLSignature(crl *pkix.CertificateList) (err os.Error) {
+ algo := getSignatureAlgorithmFromOID(crl.SignatureAlgorithm.Algorithm)
+ return c.CheckSignature(algo, crl.TBSCertList.Raw, crl.SignatureValue.RightAlign())
}
type UnhandledCriticalExtension struct{}
@@ -514,12 +479,12 @@ func (h UnhandledCriticalExtension) String() string {
}
type basicConstraints struct {
- IsCA bool "optional"
- MaxPathLen int "optional"
+ IsCA bool `asn1:"optional"`
+ MaxPathLen int `asn1:"optional"`
}
type rsaPublicKey struct {
- N asn1.RawValue
+ N *big.Int
E int
}
@@ -531,17 +496,18 @@ type policyInformation struct {
// RFC 5280, 4.2.1.10
type nameConstraints struct {
- Permitted []generalSubtree "optional,tag:0"
- Excluded []generalSubtree "optional,tag:1"
+ Permitted []generalSubtree `asn1:"optional,tag:0"`
+ Excluded []generalSubtree `asn1:"optional,tag:1"`
}
type generalSubtree struct {
- Name string "tag:2,optional,ia5"
- Min int "optional,tag:0"
- Max int "optional,tag:1"
+ Name string `asn1:"tag:2,optional,ia5"`
+ Min int `asn1:"optional,tag:0"`
+ Max int `asn1:"optional,tag:1"`
}
-func parsePublicKey(algo PublicKeyAlgorithm, asn1Data []byte) (interface{}, os.Error) {
+func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{}, os.Error) {
+ asn1Data := keyData.PublicKey.RightAlign()
switch algo {
case RSA:
p := new(rsaPublicKey)
@@ -550,19 +516,38 @@ func parsePublicKey(algo PublicKeyAlgorithm, asn1Data []byte) (interface{}, os.E
return nil, err
}
- if !rawValueIsInteger(&p.N) {
- return nil, asn1.StructuralError{"tags don't match"}
- }
-
pub := &rsa.PublicKey{
E: p.E,
- N: new(big.Int).SetBytes(p.N.Bytes),
+ N: p.N,
+ }
+ return pub, nil
+ case DSA:
+ var p *big.Int
+ _, err := asn1.Unmarshal(asn1Data, &p)
+ if err != nil {
+ return nil, err
+ }
+ paramsData := keyData.Algorithm.Parameters.FullBytes
+ params := new(dsaAlgorithmParameters)
+ _, err = asn1.Unmarshal(paramsData, params)
+ if err != nil {
+ return nil, err
+ }
+ if p.Sign() <= 0 || params.P.Sign() <= 0 || params.Q.Sign() <= 0 || params.G.Sign() <= 0 {
+ return nil, os.NewError("zero or negative DSA parameter")
+ }
+ pub := &dsa.PublicKey{
+ Parameters: dsa.Parameters{
+ P: params.P,
+ Q: params.Q,
+ G: params.G,
+ },
+ Y: p,
}
return pub, nil
default:
return nil, nil
}
-
panic("unreachable")
}
@@ -579,15 +564,19 @@ func parseCertificate(in *certificate) (*Certificate, os.Error) {
out.PublicKeyAlgorithm =
getPublicKeyAlgorithmFromOID(in.TBSCertificate.PublicKey.Algorithm.Algorithm)
var err os.Error
- out.PublicKey, err = parsePublicKey(out.PublicKeyAlgorithm, in.TBSCertificate.PublicKey.PublicKey.RightAlign())
+ out.PublicKey, err = parsePublicKey(out.PublicKeyAlgorithm, &in.TBSCertificate.PublicKey)
if err != nil {
return nil, err
}
+ if in.TBSCertificate.SerialNumber.Sign() < 0 {
+ return nil, os.NewError("negative serial number")
+ }
+
out.Version = in.TBSCertificate.Version + 1
- out.SerialNumber = in.TBSCertificate.SerialNumber.Bytes
- out.Issuer.fillFromRDNSequence(&in.TBSCertificate.Issuer)
- out.Subject.fillFromRDNSequence(&in.TBSCertificate.Subject)
+ out.SerialNumber = in.TBSCertificate.SerialNumber
+ out.Issuer.FillFromRDNSequence(&in.TBSCertificate.Issuer)
+ out.Subject.FillFromRDNSequence(&in.TBSCertificate.Subject)
out.NotBefore = in.TBSCertificate.Validity.NotBefore
out.NotAfter = in.TBSCertificate.Validity.NotAfter
@@ -611,13 +600,13 @@ func parseCertificate(in *certificate) (*Certificate, os.Error) {
}
case 19:
// RFC 5280, 4.2.1.9
- var constriants basicConstraints
- _, err := asn1.Unmarshal(e.Value, &constriants)
+ var constraints basicConstraints
+ _, err := asn1.Unmarshal(e.Value, &constraints)
if err == nil {
out.BasicConstraintsValid = true
- out.IsCA = constriants.IsCA
- out.MaxPathLen = constriants.MaxPathLen
+ out.IsCA = constraints.IsCA
+ out.MaxPathLen = constraints.MaxPathLen
continue
}
case 17:
@@ -804,7 +793,7 @@ func ParseCertificate(asn1Data []byte) (*Certificate, os.Error) {
// ParseCertificates parses one or more certificates from the given ASN.1 DER
// data. The certificates must be concatenated with no intermediate padding.
func ParseCertificates(asn1Data []byte) ([]*Certificate, os.Error) {
- v := new(vector.Vector)
+ var v []*certificate
for len(asn1Data) > 0 {
cert := new(certificate)
@@ -813,12 +802,12 @@ func ParseCertificates(asn1Data []byte) ([]*Certificate, os.Error) {
if err != nil {
return nil, err
}
- v.Push(cert)
+ v = append(v, cert)
}
- ret := make([]*Certificate, v.Len())
- for i := 0; i < v.Len(); i++ {
- cert, err := parseCertificate(v.At(i).(*certificate))
+ ret := make([]*Certificate, len(v))
+ for i, ci := range v {
+ cert, err := parseCertificate(ci)
if err != nil {
return nil, err
}
@@ -845,8 +834,8 @@ var (
oidExtensionNameConstraints = []int{2, 5, 29, 30}
)
-func buildExtensions(template *Certificate) (ret []extension, err os.Error) {
- ret = make([]extension, 7 /* maximum number of elements. */ )
+func buildExtensions(template *Certificate) (ret []pkix.Extension, err os.Error) {
+ ret = make([]pkix.Extension, 7 /* maximum number of elements. */ )
n := 0
if template.KeyUsage != 0 {
@@ -963,7 +952,7 @@ var (
// The returned slice is the certificate in DER encoding.
func CreateCertificate(rand io.Reader, template, parent *Certificate, pub *rsa.PublicKey, priv *rsa.PrivateKey) (cert []byte, err os.Error) {
asn1PublicKey, err := asn1.Marshal(rsaPublicKey{
- N: asn1.RawValue{Tag: 2, Bytes: pub.N.Bytes()},
+ N: pub.N,
E: pub.E,
})
if err != nil {
@@ -982,12 +971,12 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub *rsa.P
encodedPublicKey := asn1.BitString{BitLength: len(asn1PublicKey) * 8, Bytes: asn1PublicKey}
c := tbsCertificate{
Version: 2,
- SerialNumber: asn1.RawValue{Bytes: template.SerialNumber, Tag: 2},
- SignatureAlgorithm: algorithmIdentifier{oidSHA1WithRSA},
- Issuer: parent.Subject.toRDNSequence(),
+ SerialNumber: template.SerialNumber,
+ SignatureAlgorithm: pkix.AlgorithmIdentifier{Algorithm: oidSHA1WithRSA},
+ Issuer: parent.Subject.ToRDNSequence(),
Validity: validity{template.NotBefore, template.NotAfter},
- Subject: template.Subject.toRDNSequence(),
- PublicKey: publicKeyInfo{nil, algorithmIdentifier{oidRSA}, encodedPublicKey},
+ Subject: template.Subject.ToRDNSequence(),
+ PublicKey: publicKeyInfo{nil, pkix.AlgorithmIdentifier{Algorithm: oidRSA}, encodedPublicKey},
Extensions: extensions,
}
@@ -1010,8 +999,75 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub *rsa.P
cert, err = asn1.Marshal(certificate{
nil,
c,
- algorithmIdentifier{oidSHA1WithRSA},
+ pkix.AlgorithmIdentifier{Algorithm: oidSHA1WithRSA},
asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
})
return
}
+
+// pemCRLPrefix is the magic string that indicates that we have a PEM encoded
+// CRL.
+var pemCRLPrefix = []byte("-----BEGIN X509 CRL")
+// pemType is the type of a PEM encoded CRL.
+var pemType = "X509 CRL"
+
+// ParseCRL parses a CRL from the given bytes. It's often the case that PEM
+// encoded CRLs will appear where they should be DER encoded, so this function
+// will transparently handle PEM encoding as long as there isn't any leading
+// garbage.
+func ParseCRL(crlBytes []byte) (certList *pkix.CertificateList, err os.Error) {
+ if bytes.HasPrefix(crlBytes, pemCRLPrefix) {
+ block, _ := pem.Decode(crlBytes)
+ if block != nil && block.Type == pemType {
+ crlBytes = block.Bytes
+ }
+ }
+ return ParseDERCRL(crlBytes)
+}
+
+// ParseDERCRL parses a DER encoded CRL from the given bytes.
+func ParseDERCRL(derBytes []byte) (certList *pkix.CertificateList, err os.Error) {
+ certList = new(pkix.CertificateList)
+ _, err = asn1.Unmarshal(derBytes, certList)
+ if err != nil {
+ certList = nil
+ }
+ return
+}
+
+// CreateCRL returns a DER encoded CRL, signed by this Certificate, that
+// contains the given list of revoked certificates.
+func (c *Certificate) CreateCRL(rand io.Reader, priv *rsa.PrivateKey, revokedCerts []pkix.RevokedCertificate, now, expiry *time.Time) (crlBytes []byte, err os.Error) {
+ tbsCertList := pkix.TBSCertificateList{
+ Version: 2,
+ Signature: pkix.AlgorithmIdentifier{
+ Algorithm: oidSignatureSHA1WithRSA,
+ },
+ Issuer: c.Subject.ToRDNSequence(),
+ ThisUpdate: now,
+ NextUpdate: expiry,
+ RevokedCertificates: revokedCerts,
+ }
+
+ tbsCertListContents, err := asn1.Marshal(tbsCertList)
+ if err != nil {
+ return
+ }
+
+ h := sha1.New()
+ h.Write(tbsCertListContents)
+ digest := h.Sum()
+
+ signature, err := rsa.SignPKCS1v15(rand, priv, crypto.SHA1, digest)
+ if err != nil {
+ return
+ }
+
+ return asn1.Marshal(pkix.CertificateList{
+ TBSCertList: tbsCertList,
+ SignatureAlgorithm: pkix.AlgorithmIdentifier{
+ Algorithm: oidSignatureSHA1WithRSA,
+ },
+ SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
+ })
+}
diff --git a/libgo/go/crypto/x509/x509_test.go b/libgo/go/crypto/x509/x509_test.go
index a42113a..dc21650 100644
--- a/libgo/go/crypto/x509/x509_test.go
+++ b/libgo/go/crypto/x509/x509_test.go
@@ -7,8 +7,11 @@ package x509
import (
"asn1"
"big"
+ "crypto/dsa"
"crypto/rand"
"crypto/rsa"
+ "crypto/x509/pkix"
+ "encoding/base64"
"encoding/hex"
"encoding/pem"
"testing"
@@ -54,6 +57,12 @@ func fromBase10(base10 string) *big.Int {
return i
}
+func bigFromHexString(s string) *big.Int {
+ ret := new(big.Int)
+ ret.SetString(s, 16)
+ return ret
+}
+
var rsaPrivateKey = &rsa.PrivateKey{
PublicKey: rsa.PublicKey{
N: bigFromString("9353930466774385905609975137998169297361893554149986716853295022578535724979677252958524466350471210367835187480748268864277464700638583474144061408845077"),
@@ -200,8 +209,8 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
}
template := Certificate{
- SerialNumber: []byte{1},
- Subject: Name{
+ SerialNumber: big.NewInt(1),
+ Subject: pkix.Name{
CommonName: "test.example.com",
Organization: []string{"Acme Co"},
},
@@ -245,3 +254,178 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
return
}
}
+
+// Self-signed certificate using DSA with SHA1
+var dsaCertPem = `-----BEGIN CERTIFICATE-----
+MIIEDTCCA82gAwIBAgIJALHPghaoxeDhMAkGByqGSM44BAMweTELMAkGA1UEBhMC
+VVMxCzAJBgNVBAgTAk5DMQ8wDQYDVQQHEwZOZXd0b24xFDASBgNVBAoTC0dvb2ds
+ZSwgSW5jMRIwEAYDVQQDEwlKb24gQWxsaWUxIjAgBgkqhkiG9w0BCQEWE2pvbmFs
+bGllQGdvb2dsZS5jb20wHhcNMTEwNTE0MDMwMTQ1WhcNMTEwNjEzMDMwMTQ1WjB5
+MQswCQYDVQQGEwJVUzELMAkGA1UECBMCTkMxDzANBgNVBAcTBk5ld3RvbjEUMBIG
+A1UEChMLR29vZ2xlLCBJbmMxEjAQBgNVBAMTCUpvbiBBbGxpZTEiMCAGCSqGSIb3
+DQEJARYTam9uYWxsaWVAZ29vZ2xlLmNvbTCCAbcwggEsBgcqhkjOOAQBMIIBHwKB
+gQC8hLUnQ7FpFYu4WXTj6DKvXvz8QrJkNJCVMTpKAT7uBpobk32S5RrPKXocd4gN
+8lyGB9ggS03EVlEwXvSmO0DH2MQtke2jl9j1HLydClMf4sbx5V6TV9IFw505U1iW
+jL7awRMgxge+FsudtJK254FjMFo03ZnOQ8ZJJ9E6AEDrlwIVAJpnBn9moyP11Ox5
+Asc/5dnjb6dPAoGBAJFHd4KVv1iTVCvEG6gGiYop5DJh28hUQcN9kul+2A0yPUSC
+X93oN00P8Vh3eYgSaCWZsha7zDG53MrVJ0Zf6v/X/CoZNhLldeNOepivTRAzn+Rz
+kKUYy5l1sxYLHQKF0UGNCXfFKZT0PCmgU+PWhYNBBMn6/cIh44vp85ideo5CA4GE
+AAKBgFmifCafzeRaohYKXJgMGSEaggCVCRq5xdyDCat+wbOkjC4mfG01/um3G8u5
+LxasjlWRKTR/tcAL7t0QuokVyQaYdVypZXNaMtx1db7YBuHjj3aP+8JOQRI9xz8c
+bp5NDJ5pISiFOv4p3GZfqZPcqckDt78AtkQrmnal2txhhjF6o4HeMIHbMB0GA1Ud
+DgQWBBQVyyr7hO11ZFFpWX50298Sa3V+rzCBqwYDVR0jBIGjMIGggBQVyyr7hO11
+ZFFpWX50298Sa3V+r6F9pHsweTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAk5DMQ8w
+DQYDVQQHEwZOZXd0b24xFDASBgNVBAoTC0dvb2dsZSwgSW5jMRIwEAYDVQQDEwlK
+b24gQWxsaWUxIjAgBgkqhkiG9w0BCQEWE2pvbmFsbGllQGdvb2dsZS5jb22CCQCx
+z4IWqMXg4TAMBgNVHRMEBTADAQH/MAkGByqGSM44BAMDLwAwLAIUPtn/5j8Q1jJI
+7ggOIsgrhgUdjGQCFCsmDq1H11q9+9Wp9IMeGrTSKHIM
+-----END CERTIFICATE-----
+`
+
+func TestParseCertificateWithDsaPublicKey(t *testing.T) {
+ expectedKey := &dsa.PublicKey{
+ Parameters: dsa.Parameters{
+ P: bigFromHexString("00BC84B52743B169158BB85974E3E832AF5EFCFC42B264349095313A4A013EEE069A1B937D92E51ACF297A1C77880DF25C8607D8204B4DC45651305EF4A63B40C7D8C42D91EDA397D8F51CBC9D0A531FE2C6F1E55E9357D205C39D395358968CBEDAC11320C607BE16CB9DB492B6E78163305A34DD99CE43C64927D13A0040EB97"),
+ Q: bigFromHexString("009A67067F66A323F5D4EC7902C73FE5D9E36FA74F"),
+ G: bigFromHexString("009147778295BF5893542BC41BA806898A29E43261DBC85441C37D92E97ED80D323D44825FDDE8374D0FF15877798812682599B216BBCC31B9DCCAD527465FEAFFD7FC2A193612E575E34E7A98AF4D10339FE47390A518CB9975B3160B1D0285D1418D0977C52994F43C29A053E3D685834104C9FAFDC221E38BE9F3989D7A8E42"),
+ },
+ Y: bigFromHexString("59A27C269FCDE45AA2160A5C980C19211A820095091AB9C5DC8309AB7EC1B3A48C2E267C6D35FEE9B71BCBB92F16AC8E559129347FB5C00BEEDD10BA8915C90698755CA965735A32DC7575BED806E1E38F768FFBC24E41123DC73F1C6E9E4D0C9E692128853AFE29DC665FA993DCA9C903B7BF00B6442B9A76A5DADC6186317A"),
+ }
+ pemBlock, _ := pem.Decode([]byte(dsaCertPem))
+ cert, err := ParseCertificate(pemBlock.Bytes)
+ if err != nil {
+ t.Fatalf("Failed to parse certificate: %s", err)
+ }
+ if cert.PublicKeyAlgorithm != DSA {
+ t.Errorf("Parsed key algorithm was not DSA")
+ }
+ parsedKey, ok := cert.PublicKey.(*dsa.PublicKey)
+ if !ok {
+ t.Fatalf("Parsed key was not a DSA key: %s", err)
+ }
+ if expectedKey.Y.Cmp(parsedKey.Y) != 0 ||
+ expectedKey.P.Cmp(parsedKey.P) != 0 ||
+ expectedKey.Q.Cmp(parsedKey.Q) != 0 ||
+ expectedKey.G.Cmp(parsedKey.G) != 0 {
+ t.Fatal("Parsed key differs from expected key")
+ }
+}
+
+func TestParseCertificateWithDSASignatureAlgorithm(t *testing.T) {
+ pemBlock, _ := pem.Decode([]byte(dsaCertPem))
+ cert, err := ParseCertificate(pemBlock.Bytes)
+ if err != nil {
+ t.Fatalf("Failed to parse certificate: %s", err)
+ }
+ if cert.SignatureAlgorithm != DSAWithSHA1 {
+ t.Errorf("Parsed signature algorithm was not DSAWithSHA1")
+ }
+}
+
+func TestVerifyCertificateWithDSASignature(t *testing.T) {
+ pemBlock, _ := pem.Decode([]byte(dsaCertPem))
+ cert, err := ParseCertificate(pemBlock.Bytes)
+ if err != nil {
+ t.Fatalf("Failed to parse certificate: %s", err)
+ }
+ // test cert is self-signed
+ if err = cert.CheckSignatureFrom(cert); err != nil {
+ t.Fatalf("DSA Certificate verfication failed: %s", err)
+ }
+}
+
+const pemCertificate = `-----BEGIN CERTIFICATE-----
+MIIB5DCCAZCgAwIBAgIBATALBgkqhkiG9w0BAQUwLTEQMA4GA1UEChMHQWNtZSBDbzEZMBcGA1UE
+AxMQdGVzdC5leGFtcGxlLmNvbTAeFw03MDAxMDEwMDE2NDBaFw03MDAxMDIwMzQ2NDBaMC0xEDAO
+BgNVBAoTB0FjbWUgQ28xGTAXBgNVBAMTEHRlc3QuZXhhbXBsZS5jb20wWjALBgkqhkiG9w0BAQED
+SwAwSAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0fd7Ai2KW5ToIwzFo
+fvJcS/STa6HA5gQenRUCAwEAAaOBnjCBmzAOBgNVHQ8BAf8EBAMCAAQwDwYDVR0TAQH/BAUwAwEB
+/zANBgNVHQ4EBgQEAQIDBDAPBgNVHSMECDAGgAQBAgMEMBsGA1UdEQQUMBKCEHRlc3QuZXhhbXBs
+ZS5jb20wDwYDVR0gBAgwBjAEBgIqAzAqBgNVHR4EIzAhoB8wDoIMLmV4YW1wbGUuY29tMA2CC2V4
+YW1wbGUuY29tMAsGCSqGSIb3DQEBBQNBAHKZKoS1wEQOGhgklx4+/yFYQlnqwKXvar/ZecQvJwui
+0seMQnwBhwdBkHfVIU2Fu5VUMRyxlf0ZNaDXcpU581k=
+-----END CERTIFICATE-----`
+
+func TestCRLCreation(t *testing.T) {
+ block, _ := pem.Decode([]byte(pemPrivateKey))
+ priv, _ := ParsePKCS1PrivateKey(block.Bytes)
+ block, _ = pem.Decode([]byte(pemCertificate))
+ cert, _ := ParseCertificate(block.Bytes)
+
+ now := time.SecondsToUTC(1000)
+ expiry := time.SecondsToUTC(10000)
+
+ revokedCerts := []pkix.RevokedCertificate{
+ {
+ SerialNumber: big.NewInt(1),
+ RevocationTime: now,
+ },
+ {
+ SerialNumber: big.NewInt(42),
+ RevocationTime: now,
+ },
+ }
+
+ crlBytes, err := cert.CreateCRL(rand.Reader, priv, revokedCerts, now, expiry)
+ if err != nil {
+ t.Errorf("error creating CRL: %s", err)
+ }
+
+ _, err = ParseDERCRL(crlBytes)
+ if err != nil {
+ t.Errorf("error reparsing CRL: %s", err)
+ }
+}
+
+func fromBase64(in string) []byte {
+ out := make([]byte, base64.StdEncoding.DecodedLen(len(in)))
+ _, err := base64.StdEncoding.Decode(out, []byte(in))
+ if err != nil {
+ panic("failed to base64 decode")
+ }
+ return out
+}
+
+func TestParseDERCRL(t *testing.T) {
+ derBytes := fromBase64(derCRLBase64)
+ certList, err := ParseDERCRL(derBytes)
+ if err != nil {
+ t.Errorf("error parsing: %s", err)
+ return
+ }
+ numCerts := len(certList.TBSCertList.RevokedCertificates)
+ expected := 88
+ if numCerts != expected {
+ t.Errorf("bad number of revoked certificates. got: %d want: %d", numCerts, expected)
+ }
+
+ if certList.HasExpired(1302517272) {
+ t.Errorf("CRL has expired (but shouldn't have)")
+ }
+
+ // Can't check the signature here without a package cycle.
+}
+
+func TestParsePEMCRL(t *testing.T) {
+ pemBytes := fromBase64(pemCRLBase64)
+ certList, err := ParseCRL(pemBytes)
+ if err != nil {
+ t.Errorf("error parsing: %s", err)
+ return
+ }
+ numCerts := len(certList.TBSCertList.RevokedCertificates)
+ expected := 2
+ if numCerts != expected {
+ t.Errorf("bad number of revoked certificates. got: %d want: %d", numCerts, expected)
+ }
+
+ if certList.HasExpired(1302517272) {
+ t.Errorf("CRL has expired (but shouldn't have)")
+ }
+
+ // Can't check the signature here without a package cycle.
+}
+
+const derCRLBase64 = "MIINqzCCDJMCAQEwDQYJKoZIhvcNAQEFBQAwVjEZMBcGA1UEAxMQUEtJIEZJTk1FQ0NBTklDQTEVMBMGA1UEChMMRklOTUVDQ0FOSUNBMRUwEwYDVQQLEwxGSU5NRUNDQU5JQ0ExCzAJBgNVBAYTAklUFw0xMTA1MDQxNjU3NDJaFw0xMTA1MDQyMDU3NDJaMIIMBzAhAg4Ze1od49Lt1qIXBydAzhcNMDkwNzE2MDg0MzIyWjAAMCECDl0HSL9bcZ1Ci/UHJ0DPFw0wOTA3MTYwODQzMTNaMAAwIQIOESB9tVAmX3cY7QcnQNAXDTA5MDcxNjA4NDUyMlowADAhAg4S1tGAQ3mHt8uVBydA1RcNMDkwODA0MTUyNTIyWjAAMCECDlQ249Y7vtC25ScHJ0DWFw0wOTA4MDQxNTI1MzdaMAAwIQIOISMop3NkA4PfYwcnQNkXDTA5MDgwNDExMDAzNFowADAhAg56/BMoS29KEShTBydA2hcNMDkwODA0MTEwMTAzWjAAMCECDnBp/22HPH5CSWoHJ0DbFw0wOTA4MDQxMDU0NDlaMAAwIQIOV9IP+8CD8bK+XAcnQNwXDTA5MDgwNDEwNTcxN1owADAhAg4v5aRz0IxWqYiXBydA3RcNMDkwODA0MTA1NzQ1WjAAMCECDlOU34VzvZAybQwHJ0DeFw0wOTA4MDQxMDU4MjFaMAAwIAINO4CD9lluIxcwBydBAxcNMDkwNzIyMTUzMTU5WjAAMCECDgOllfO8Y1QA7/wHJ0ExFw0wOTA3MjQxMTQxNDNaMAAwIQIOJBX7jbiCdRdyjgcnQUQXDTA5MDkxNjA5MzAwOFowADAhAg5iYSAgmDrlH/RZBydBRRcNMDkwOTE2MDkzMDE3WjAAMCECDmu6k6srP3jcMaQHJ0FRFw0wOTA4MDQxMDU2NDBaMAAwIQIOX8aHlO0V+WVH4QcnQVMXDTA5MDgwNDEwNTcyOVowADAhAg5flK2rg3NnsRgDBydBzhcNMTEwMjAxMTUzMzQ2WjAAMCECDg35yJDL1jOPTgoHJ0HPFw0xMTAyMDExNTM0MjZaMAAwIQIOMyFJ6+e9iiGVBQcnQdAXDTA5MDkxODEzMjAwNVowADAhAg5Emb/Oykucmn8fBydB1xcNMDkwOTIxMTAxMDQ3WjAAMCECDjQKCncV+MnUavMHJ0HaFw0wOTA5MjIwODE1MjZaMAAwIQIOaxiFUt3dpd+tPwcnQfQXDTEwMDYxODA4NDI1MVowADAhAg5G7P8nO0tkrMt7BydB9RcNMTAwNjE4MDg0MjMwWjAAMCECDmTCC3SXhmDRst4HJ0H2Fw0wOTA5MjgxMjA3MjBaMAAwIQIOHoGhUr/pRwzTKgcnQfcXDTA5MDkyODEyMDcyNFowADAhAg50wrcrCiw8mQmPBydCBBcNMTAwMjE2MTMwMTA2WjAAMCECDifWmkvwyhEqwEcHJ0IFFw0xMDAyMTYxMzAxMjBaMAAwIQIOfgPmlW9fg+osNgcnQhwXDTEwMDQxMzA5NTIwMFowADAhAg4YHAGuA6LgCk7tBydCHRcNMTAwNDEzMDk1MTM4WjAAMCECDi1zH1bxkNJhokAHJ0IsFw0xMDA0MTMwOTU5MzBaMAAwIQIOMipNccsb/wo2fwcnQi0XDTEwMDQxMzA5NTkwMFowADAhAg46lCmvPl4GpP6ABydCShcNMTAwMTE5MDk1MjE3WjAAMCECDjaTcaj+wBpcGAsHJ0JLFw0xMDAxMTkwOTUyMzRaMAAwIQIOOMC13EOrBuxIOQcnQloXDTEwMDIwMTA5NDcwNVowADAhAg5KmZl+krz4RsmrBydCWxcNMTAwMjAxMDk0NjQwWjAAMCECDmLG3zQJ/fzdSsUHJ0JiFw0xMDAzMDEwOTUxNDBaMAAwIQIOP39ksgHdojf4owcnQmMXDTEwMDMwMTA5NTExN1owADAhAg4LDQzvWNRlD6v9BydCZBcNMTAwMzAxMDk0NjIyWjAAMCECDkmNfeclaFhIaaUHJ0JlFw0xMDAzMDEwOTQ2MDVaMAAwIQIOT/qWWfpH/m8NTwcnQpQXDTEwMDUxMTA5MTgyMVowADAhAg5m/ksYxvCEgJSvBydClRcNMTAwNTExMDkxODAxWjAAMCECDgvf3Ohq6JOPU9AHJ0KWFw0xMDA1MTEwOTIxMjNaMAAwIQIOKSPas10z4jNVIQcnQpcXDTEwMDUxMTA5MjEwMlowADAhAg4mCWmhoZ3lyKCDBydCohcNMTEwNDI4MTEwMjI1WjAAMCECDkeiyRsBMK0Gvr4HJ0KjFw0xMTA0MjgxMTAyMDdaMAAwIQIOa09b/nH2+55SSwcnQq4XDTExMDQwMTA4Mjk0NlowADAhAg5O7M7iq7gGplr1BydCrxcNMTEwNDAxMDgzMDE3WjAAMCECDjlT6mJxUjTvyogHJ0K1Fw0xMTAxMjcxNTQ4NTJaMAAwIQIODS/l4UUFLe21NAcnQrYXDTExMDEyNzE1NDgyOFowADAhAg5lPRA0XdOUF6lSBydDHhcNMTEwMTI4MTQzNTA1WjAAMCECDixKX4fFGGpENwgHJ0MfFw0xMTAxMjgxNDM1MzBaMAAwIQIORNBkqsPnpKTtbAcnQ08XDTEwMDkwOTA4NDg0MlowADAhAg5QL+EMM3lohedEBydDUBcNMTAwOTA5MDg0ODE5WjAAMCECDlhDnHK+HiTRAXcHJ0NUFw0xMDEwMTkxNjIxNDBaMAAwIQIOdBFqAzq/INz53gcnQ1UXDTEwMTAxOTE2MjA0NFowADAhAg4OjR7s8MgKles1BydDWhcNMTEwMTI3MTY1MzM2WjAAMCECDmfR/elHee+d0SoHJ0NbFw0xMTAxMjcxNjUzNTZaMAAwIQIOBTKv2ui+KFMI+wcnQ5YXDTEwMDkxNTEwMjE1N1owADAhAg49F3c/GSah+oRUBydDmxcNMTEwMTI3MTczMjMzWjAAMCECDggv4I61WwpKFMMHJ0OcFw0xMTAxMjcxNzMyNTVaMAAwIQIOXx/Y8sEvwS10LAcnQ6UXDTExMDEyODExMjkzN1owADAhAg5LSLbnVrSKaw/9BydDphcNMTEwMTI4MTEyOTIwWjAAMCECDmFFoCuhKUeACQQHJ0PfFw0xMTAxMTExMDE3MzdaMAAwIQIOQTDdFh2fSPF6AAcnQ+AXDTExMDExMTEwMTcxMFowADAhAg5B8AOXX61FpvbbBydD5RcNMTAxMDA2MTAxNDM2WjAAMCECDh41P2Gmi7PkwI4HJ0PmFw0xMDEwMDYxMDE2MjVaMAAwIQIOWUHGLQCd+Ale9gcnQ/0XDTExMDUwMjA3NTYxMFowADAhAg5Z2c9AYkikmgWOBydD/hcNMTEwNTAyMDc1NjM0WjAAMCECDmf/UD+/h8nf+74HJ0QVFw0xMTA0MTUwNzI4MzNaMAAwIQIOICvj4epy3MrqfwcnRBYXDTExMDQxNTA3Mjg1NlowADAhAg4bouRMfOYqgv4xBydEHxcNMTEwMzA4MTYyNDI1WjAAMCECDhebWHGoKiTp7pEHJ0QgFw0xMTAzMDgxNjI0NDhaMAAwIQIOX+qnxxAqJ8LtawcnRDcXDTExMDEzMTE1MTIyOFowADAhAg4j0fICqZ+wkOdqBydEOBcNMTEwMTMxMTUxMTQxWjAAMCECDhmXjsV4SUpWtAMHJ0RLFw0xMTAxMjgxMTI0MTJaMAAwIQIODno/w+zG43kkTwcnREwXDTExMDEyODExMjM1MlowADAhAg4b1gc88767Fr+LBydETxcNMTEwMTI4MTEwMjA4WjAAMCECDn+M3Pa1w2nyFeUHJ0RQFw0xMTAxMjgxMDU4NDVaMAAwIQIOaduoyIH61tqybAcnRJUXDTEwMTIxNTA5NDMyMlowADAhAg4nLqQPkyi3ESAKBydElhcNMTAxMjE1MDk0MzM2WjAAMCECDi504NIMH8578gQHJ0SbFw0xMTAyMTQxNDA1NDFaMAAwIQIOGuaM8PDaC5u1egcnRJwXDTExMDIxNDE0MDYwNFowADAhAg4ehYq/BXGnB5PWBydEnxcNMTEwMjA0MDgwOTUxWjAAMCECDkSD4eS4FxW5H20HJ0SgFw0xMTAyMDQwODA5MjVaMAAwIQIOOCcb6ilYObt1egcnRKEXDTExMDEyNjEwNDEyOVowADAhAg58tISWCCwFnKGnBydEohcNMTEwMjA0MDgxMzQyWjAAMCECDn5rjtabY/L/WL0HJ0TJFw0xMTAyMDQxMTAzNDFaMAAwDQYJKoZIhvcNAQEFBQADggEBAGnF2Gs0+LNiYCW1Ipm83OXQYP/bd5tFFRzyz3iepFqNfYs4D68/QihjFoRHQoXEB0OEe1tvaVnnPGnEOpi6krwekquMxo4H88B5SlyiFIqemCOIss0SxlCFs69LmfRYvPPvPEhoXtQ3ZThe0UvKG83GOklhvGl6OaiRf4Mt+m8zOT4Wox/j6aOBK6cw6qKCdmD+Yj1rrNqFGg1CnSWMoD6S6mwNgkzwdBUJZ22BwrzAAo4RHa2Uy3ef1FjwD0XtU5N3uDSxGGBEDvOe5z82rps3E22FpAA8eYl8kaXtmWqyvYU0epp4brGuTxCuBMCAsxt/OjIjeNNQbBGkwxgfYA0="
+
+const pemCRLBase64 = "LS0tLS1CRUdJTiBYNTA5IENSTC0tLS0tDQpNSUlCOWpDQ0FWOENBUUV3RFFZSktvWklodmNOQVFFRkJRQXdiREVhTUJnR0ExVUVDaE1SVWxOQklGTmxZM1Z5DQphWFI1SUVsdVl5NHhIakFjQmdOVkJBTVRGVkpUUVNCUWRXSnNhV01nVW05dmRDQkRRU0IyTVRFdU1Dd0dDU3FHDQpTSWIzRFFFSkFSWWZjbk5oYTJWdmJuSnZiM1J6YVdkdVFISnpZWE5sWTNWeWFYUjVMbU52YlJjTk1URXdNakl6DQpNVGt5T0RNd1doY05NVEV3T0RJeU1Ua3lPRE13V2pDQmpEQktBaEVBckRxb2g5RkhKSFhUN09QZ3V1bjQrQmNODQpNRGt4TVRBeU1UUXlOekE1V2pBbU1Bb0dBMVVkRlFRRENnRUpNQmdHQTFVZEdBUVJHQTh5TURBNU1URXdNakUwDQpNalExTlZvd1BnSVJBTEd6blowOTVQQjVhQU9MUGc1N2ZNTVhEVEF5TVRBeU16RTBOVEF4TkZvd0dqQVlCZ05WDQpIUmdFRVJnUE1qQXdNakV3TWpNeE5EVXdNVFJhb0RBd0xqQWZCZ05WSFNNRUdEQVdnQlQxVERGNlVRTS9MTmVMDQpsNWx2cUhHUXEzZzltekFMQmdOVkhSUUVCQUlDQUlRd0RRWUpLb1pJaHZjTkFRRUZCUUFEZ1lFQUZVNUFzNk16DQpxNVBSc2lmYW9iUVBHaDFhSkx5QytNczVBZ2MwYld5QTNHQWR4dXI1U3BQWmVSV0NCamlQL01FSEJXSkNsQkhQDQpHUmNxNXlJZDNFakRrYUV5eFJhK2k2N0x6dmhJNmMyOUVlNks5cFNZd2ppLzdSVWhtbW5Qclh0VHhsTDBsckxyDQptUVFKNnhoRFJhNUczUUE0Q21VZHNITnZicnpnbUNZcHZWRT0NCi0tLS0tRU5EIFg1MDkgQ1JMLS0tLS0NCg0K"
diff --git a/libgo/go/crypto/xtea/block.go b/libgo/go/crypto/xtea/block.go
index 3ac36d0..bf5d245 100644
--- a/libgo/go/crypto/xtea/block.go
+++ b/libgo/go/crypto/xtea/block.go
@@ -22,7 +22,7 @@ func blockToUint32(src []byte) (uint32, uint32) {
return r0, r1
}
-// uint32ToBlock writes two unint32s into an 8 byte data block.
+// uint32ToBlock writes two uint32s into an 8 byte data block.
// Values are written as big endian.
func uint32ToBlock(v0, v1 uint32, dst []byte) {
dst[0] = byte(v0 >> 24)
diff --git a/libgo/go/crypto/xtea/cipher.go b/libgo/go/crypto/xtea/cipher.go
index f2a5da0..b3fba3c8 100644
--- a/libgo/go/crypto/xtea/cipher.go
+++ b/libgo/go/crypto/xtea/cipher.go
@@ -48,13 +48,13 @@ func NewCipher(key []byte) (*Cipher, os.Error) {
// BlockSize returns the XTEA block size, 8 bytes.
// It is necessary to satisfy the Cipher interface in the
-// package "crypto/block".
+// package "crypto/cipher".
func (c *Cipher) BlockSize() int { return BlockSize }
// Encrypt encrypts the 8 byte buffer src using the key and stores the result in dst.
// Note that for amounts of data larger than a block,
// it is not safe to just call Encrypt on successive blocks;
-// instead, use an encryption mode like CBC (see crypto/block/cbc.go).
+// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go).
func (c *Cipher) Encrypt(dst, src []byte) { encryptBlock(c, dst, src) }
// Decrypt decrypts the 8 byte buffer src using the key k and stores the result in dst.
diff --git a/libgo/go/crypto/xtea/xtea_test.go b/libgo/go/crypto/xtea/xtea_test.go
index 03934f1..217d96a 100644
--- a/libgo/go/crypto/xtea/xtea_test.go
+++ b/libgo/go/crypto/xtea/xtea_test.go
@@ -8,7 +8,7 @@ import (
"testing"
)
-// A sample test key for when we just want to initialise a cipher
+// A sample test key for when we just want to initialize a cipher
var testKey = []byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}
// Test that the block size for XTEA is correct
@@ -26,12 +26,12 @@ func TestBlocksize(t *testing.T) {
result := c.BlockSize()
if result != 8 {
- t.Errorf("BlockSize function - expected 8, gotr %d", result)
+ t.Errorf("BlockSize function - expected 8, got %d", result)
return
}
}
-// A series of test values to confirm that the Cipher.table array was initialised correctly
+// A series of test values to confirm that the Cipher.table array was initialized correctly
var testTable = []uint32{
0x00112233, 0x6B1568B8, 0xE28CE030, 0xC5089E2D, 0xC5089E2D, 0x1EFBD3A2, 0xA7845C2A, 0x78EF0917,
0x78EF0917, 0x172682D0, 0x5B6AC714, 0x822AC955, 0x3DE68511, 0xDC1DFECA, 0x2062430E, 0x3611343F,
@@ -43,7 +43,7 @@ var testTable = []uint32{
0x4E22726F, 0x309E306C, 0x309E306C, 0x8A9165E1, 0x1319EE69, 0xF595AC66, 0xF595AC66, 0x4F88E1DB,
}
-// Test that the cipher context is initialised correctly
+// Test that the cipher context is initialized correctly
func TestCipherInit(t *testing.T) {
c, err := NewCipher(testKey)
if err != nil {
@@ -53,7 +53,7 @@ func TestCipherInit(t *testing.T) {
for i := 0; i < len(c.table); i++ {
if c.table[i] != testTable[i] {
- t.Errorf("NewCipher() failed to initialise Cipher.table[%d] correctly. Expected %08X, got %08X", i, testTable[i], c.table[i])
+ t.Errorf("NewCipher() failed to initialize Cipher.table[%d] correctly. Expected %08X, got %08X", i, testTable[i], c.table[i])
break
}
}