Commit e7db6d78 authored by Jonathan Allie's avatar Jonathan Allie Committed by Adam Langley

crypto/x509: add support for parsing and verifying DSA signatures

(DSA with SHA1, DSA with SHA256). Cleanup getSignatureFromOID
function.

R=agl, agl, rsc
CC=golang-dev
https://golang.org/cl/4530055
parent bda36cf3
...@@ -120,6 +120,7 @@ Jim McGrath <jimmc2@gmail.com> ...@@ -120,6 +120,7 @@ Jim McGrath <jimmc2@gmail.com>
Joe Poirier <jdpoirier@gmail.com> Joe Poirier <jdpoirier@gmail.com>
Johan Euphrosine <proppy@google.com> Johan Euphrosine <proppy@google.com>
John DeNero <denero@google.com> John DeNero <denero@google.com>
Jonathan Allie <jonallie@google.com>
Jonathan Wills <runningwild@gmail.com> Jonathan Wills <runningwild@gmail.com>
Jos Visser <josv@google.com> Jos Visser <josv@google.com>
Jose Luis Vázquez González <josvazg@gmail.com> Jose Luis Vázquez González <josvazg@gmail.com>
......
...@@ -173,6 +173,10 @@ type dsaAlgorithmParameters struct { ...@@ -173,6 +173,10 @@ type dsaAlgorithmParameters struct {
P, Q, G asn1.RawValue P, Q, G asn1.RawValue
} }
type dsaSignature struct {
R, S asn1.RawValue
}
type algorithmIdentifier struct { type algorithmIdentifier struct {
Algorithm asn1.ObjectIdentifier Algorithm asn1.ObjectIdentifier
Parameters asn1.RawValue "optional" Parameters asn1.RawValue "optional"
...@@ -218,6 +222,8 @@ const ( ...@@ -218,6 +222,8 @@ const (
SHA256WithRSA SHA256WithRSA
SHA384WithRSA SHA384WithRSA
SHA512WithRSA SHA512WithRSA
DSAWithSHA1
DSAWithSHA256
) )
type PublicKeyAlgorithm int type PublicKeyAlgorithm int
...@@ -322,25 +328,69 @@ func (n Name) toRDNSequence() (ret rdnSequence) { ...@@ -322,25 +328,69 @@ func (n Name) toRDNSequence() (ret rdnSequence) {
return ret return ret
} }
func getSignatureAlgorithmFromOID(oid []int) SignatureAlgorithm { // OIDs for signature algorithms
if len(oid) == 7 && oid[0] == 1 && oid[1] == 2 && oid[2] == 840 && //
oid[3] == 113549 && oid[4] == 1 && oid[5] == 1 { // pkcs-1 OBJECT IDENTIFIER ::= {
switch oid[6] { // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 }
case 2: //
return MD2WithRSA //
case 4: // RFC 3279 2.2.1 RSA Signature Algorithms
return MD5WithRSA //
case 5: // md2WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 2 }
return SHA1WithRSA //
case 11: // md5WithRSAEncryption OBJECT IDENTIFER ::= { pkcs-1 4 }
return SHA256WithRSA //
case 12: // sha-1WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 5 }
return SHA384WithRSA //
case 13: // dsaWithSha1 OBJECT IDENTIFIER ::= {
return SHA512WithRSA // 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 (
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}
)
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 return UnknownSignatureAlgorithm
} }
...@@ -513,9 +563,9 @@ func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature ...@@ -513,9 +563,9 @@ func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature
var hashType crypto.Hash var hashType crypto.Hash
switch algo { switch algo {
case SHA1WithRSA: case SHA1WithRSA, DSAWithSHA1:
hashType = crypto.SHA1 hashType = crypto.SHA1
case SHA256WithRSA: case SHA256WithRSA, DSAWithSHA256:
hashType = crypto.SHA256 hashType = crypto.SHA256
case SHA384WithRSA: case SHA384WithRSA:
hashType = crypto.SHA384 hashType = crypto.SHA384
...@@ -530,15 +580,28 @@ func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature ...@@ -530,15 +580,28 @@ func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature
return UnsupportedAlgorithmError{} return UnsupportedAlgorithmError{}
} }
pub, ok := c.PublicKey.(*rsa.PublicKey)
if !ok {
return UnsupportedAlgorithmError{}
}
h.Write(signed) h.Write(signed)
digest := h.Sum() digest := h.Sum()
return rsa.VerifyPKCS1v15(pub, hashType, digest, 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 !rawValueIsInteger(&dsaSig.R) || !rawValueIsInteger(&dsaSig.S) {
return asn1.StructuralError{"tags don't match"}
}
r := new(big.Int).SetBytes(dsaSig.R.Bytes)
s := new(big.Int).SetBytes(dsaSig.S.Bytes)
if !dsa.Verify(pub, digest, r, s) {
return os.ErrorString("DSA verification failure")
}
return
}
return UnsupportedAlgorithmError{}
} }
// CheckCRLSignature checks that the signature in crl is from c. // CheckCRLSignature checks that the signature in crl is from c.
......
...@@ -253,6 +253,7 @@ func TestCreateSelfSignedCertificate(t *testing.T) { ...@@ -253,6 +253,7 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
} }
} }
// Self-signed certificate using DSA with SHA1
var dsaCertPem = `-----BEGIN CERTIFICATE----- var dsaCertPem = `-----BEGIN CERTIFICATE-----
MIIEDTCCA82gAwIBAgIJALHPghaoxeDhMAkGByqGSM44BAMweTELMAkGA1UEBhMC MIIEDTCCA82gAwIBAgIJALHPghaoxeDhMAkGByqGSM44BAMweTELMAkGA1UEBhMC
VVMxCzAJBgNVBAgTAk5DMQ8wDQYDVQQHEwZOZXd0b24xFDASBgNVBAoTC0dvb2ds VVMxCzAJBgNVBAgTAk5DMQ8wDQYDVQQHEwZOZXd0b24xFDASBgNVBAoTC0dvb2ds
...@@ -307,3 +308,26 @@ func TestParseCertificateWithDsaPublicKey(t *testing.T) { ...@@ -307,3 +308,26 @@ func TestParseCertificateWithDsaPublicKey(t *testing.T) {
t.Fatal("Parsed key differs from expected key") 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.Fatal("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.Fatal("Failed to parse certificate: %s", err)
}
// test cert is self-signed
if err = cert.CheckSignatureFrom(cert); err != nil {
t.Fatal("DSA Certificate verfication failed: %s", err)
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment