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>
Joe Poirier <jdpoirier@gmail.com>
Johan Euphrosine <proppy@google.com>
John DeNero <denero@google.com>
Jonathan Allie <jonallie@google.com>
Jonathan Wills <runningwild@gmail.com>
Jos Visser <josv@google.com>
Jose Luis Vázquez González <josvazg@gmail.com>
......
......@@ -173,6 +173,10 @@ type dsaAlgorithmParameters struct {
P, Q, G asn1.RawValue
}
type dsaSignature struct {
R, S asn1.RawValue
}
type algorithmIdentifier struct {
Algorithm asn1.ObjectIdentifier
Parameters asn1.RawValue "optional"
......@@ -218,6 +222,8 @@ const (
SHA256WithRSA
SHA384WithRSA
SHA512WithRSA
DSAWithSHA1
DSAWithSHA256
)
type PublicKeyAlgorithm int
......@@ -322,25 +328,69 @@ func (n Name) toRDNSequence() (ret rdnSequence) {
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
}
}
// 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 (
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
}
......@@ -513,9 +563,9 @@ func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature
var hashType crypto.Hash
switch algo {
case SHA1WithRSA:
case SHA1WithRSA, DSAWithSHA1:
hashType = crypto.SHA1
case SHA256WithRSA:
case SHA256WithRSA, DSAWithSHA256:
hashType = crypto.SHA256
case SHA384WithRSA:
hashType = crypto.SHA384
......@@ -530,15 +580,28 @@ func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature
return UnsupportedAlgorithmError{}
}
pub, ok := c.PublicKey.(*rsa.PublicKey)
if !ok {
return UnsupportedAlgorithmError{}
}
h.Write(signed)
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.
......
......@@ -253,6 +253,7 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
}
}
// Self-signed certificate using DSA with SHA1
var dsaCertPem = `-----BEGIN CERTIFICATE-----
MIIEDTCCA82gAwIBAgIJALHPghaoxeDhMAkGByqGSM44BAMweTELMAkGA1UEBhMC
VVMxCzAJBgNVBAgTAk5DMQ8wDQYDVQQHEwZOZXd0b24xFDASBgNVBAoTC0dvb2ds
......@@ -307,3 +308,26 @@ func TestParseCertificateWithDsaPublicKey(t *testing.T) {
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