pub key representation parsing 2/..

This commit is contained in:
Stéphane Depierrepont aka Toorop
2015-05-12 18:21:41 +02:00
parent 7206fc7daf
commit 944e6d3610
3 changed files with 106 additions and 4 deletions

View File

@@ -243,7 +243,10 @@ func Verify(email *[]byte) (VerifyOutput, error) {
} }
// we do not set quesry method because if it's other validation failed earlier // we do not set quesry method because if it's other validation failed earlier
pubKey, err := newPubKeyFromDnsTxt(dkimHeader.Selector, dkimHeader.Domain) pubKey, verifyOutputOnError, err := newPubKeyFromDnsTxt(dkimHeader.Selector, dkimHeader.Domain)
if err != nil {
return verifyOutputOnError, err
}
println(pubKey) println(pubKey)
return SUCCESS, nil return SUCCESS, nil

View File

@@ -53,9 +53,30 @@ var (
// Version not supported // Version not supported
ErrDkimVersionNotsupported = errors.New("incompatible version") ErrDkimVersionNotsupported = errors.New("incompatible version")
// Query method unsopported // Query method unsupported
errQueryMethodNotsupported = errors.New("query method not supported") errQueryMethodNotsupported = errors.New("query method not supported")
// ErrVerifyBodyHash when body hash doesn't verify // ErrVerifyBodyHash when body hash doesn't verify
ErrVerifyBodyHash = errors.New("body hash did not verify") ErrVerifyBodyHash = errors.New("body hash did not verify")
// ErrVerifyNoKeyForSignature
ErrVerifyNoKeyForSignature = errors.New("no key for verify")
// ErrVerifyKeyUnavailable when service (dns) is anavailable
ErrVerifyKeyUnavailable = errors.New("key unavailable")
// ErrVerifyTagVMustBeTheFirst if present the v tag must be the firts in the record
ErrVerifyTagVMustBeTheFirst = errors.New("pub key syntax error: v tag must be the first")
// ErrVerifyVersionMusBeDkim1 if présent flag v (version) must be DKIM1
ErrVerifyVersionMusBeDkim1 = errors.New("flag v must be set to DKIM1")
// ErrVerifyBadKeyType bad type for pub key (only rsa is accepted)
ErrVerifyBadKeyType = errors.New("bad type for key type")
// ErrVerifyRevokedKey key(s) for this selector is revoked (p is empty)
ErrVerifyRevokedKey = errors.New("revoked key")
// ErrVerifyBadKey when we can't parse pubkey
ErrVerifyBadKey = errors.New("unable to parse pub key")
) )

View File

@@ -2,8 +2,11 @@ package dkim
import ( import (
"crypto/rsa" "crypto/rsa"
"crypto/x509"
"encoding/base64"
"fmt" "fmt"
"net" "net"
"strings"
) )
// pubKeyRep represents a parsed version of public key record // pubKeyRep represents a parsed version of public key record
@@ -18,9 +21,84 @@ type pubKeyRep struct {
FlagIMustBeD bool // flag i FlagIMustBeD bool // flag i
} }
func newPubKeyFromDnsTxt(selector, domain string) (*pubKeyRep, error) { func newPubKeyFromDnsTxt(selector, domain string) (*pubKeyRep, VerifyOutput, error) {
txt, err := net.LookupTXT(selector + "._domainkey." + domain) txt, err := net.LookupTXT(selector + "._domainkey." + domain)
if err != nil {
if strings.HasSuffix(err.Error(), "no such host") {
return nil, PERMFAIL, ErrVerifyNoKeyForSignature
} else {
return nil, TEMPFAIL, ErrVerifyKeyUnavailable
}
}
// empty record
if len(txt) == 0 {
return nil, PERMFAIL, ErrVerifyNoKeyForSignature
}
pkr := new(pubKeyRep)
pkr.Version = "DKIM1"
pkr.HashAlgo = []string{"sha1", "sha256"}
pkr.KeyType = "rsa"
// parsing, we keep the first record
// TODO: if there is multiple record
p := strings.Split(txt[0], ";")
for i, data := range p {
keyVal := strings.SplitN(data, "=", 2)
switch strings.ToLower(strings.TrimSpace(keyVal[0])) {
case "v":
// RFC: is this tag is specified it MUST be the first in the record
if i != 0 {
return nil, PERMFAIL, ErrVerifyTagVMustBeTheFirst
}
pkr.Version = strings.TrimSpace(keyVal[1])
if pkr.Version != "DKIM1" {
return nil, PERMFAIL, ErrVerifyVersionMusBeDkim1
}
case "h":
p := strings.Split(strings.ToLower(keyVal[1]), ":")
pkr.HashAlgo = []string{}
for _, h := range p {
h = strings.TrimSpace(h)
if h == "sha1" || h == "sha256" {
pkr.HashAlgo = append(pkr.HashAlgo, h)
}
}
// if empty switch back to default
if len(pkr.HashAlgo) == 0 {
pkr.HashAlgo = []string{"sha1", "sha256"}
}
case "k":
if strings.ToLower(strings.TrimSpace(keyVal[1])) != "rsa" {
return nil, PERMFAIL, ErrVerifyBadKeyType
}
case "n":
pkr.Note = strings.TrimSpace(keyVal[1])
case "p":
rawkey := strings.TrimSpace(keyVal[1])
if rawkey == "" {
return nil, PERMFAIL, ErrVerifyRevokedKey
}
// x509.ParsePKIXPublicKey(Dkim.PublicKey.PublicKey)
un64, err := base64.StdEncoding.DecodeString(rawkey)
if err != nil {
return nil, PERMFAIL, ErrVerifyBadKey
}
pk, err := x509.ParsePKIXPublicKey(un64)
pkr.PubKey = *pk.(*rsa.PublicKey)
// HERE
case "s":
case "t":
}
}
// TODO: If no pubkey
fmt.Println(txt, err) fmt.Println(txt, err)
return nil, nil return nil, SUCCESS, nil
} }