WIP extract mime body and check signature

This commit is contained in:
Kay Lukas 2018-09-04 23:40:35 +02:00
parent dccb3ba50b
commit 34babb3b90

158
mime.go
View file

@ -11,6 +11,10 @@ import (
log "github.com/Sirupsen/logrus"
"mime"
"mime/multipart"
"bufio"
"fmt"
"golang.org/x/crypto/openpgp/packet"
"golang.org/x/crypto/openpgp"
)
@ -29,16 +33,51 @@ func DecodePart(partReader io.Reader, header textproto.MIMEHeader) (decodedPart
// them as a string
type SignatureCollector struct {
target pmmime.VisitAcceptor
config packet.Config
keyring openpgp.KeyRing
target pmmime.VisitAcceptor
signature string
verified int
}
func NewSignatureCollector(targetAccepter pmmime.VisitAcceptor) *SignatureCollector {
func NewSignatureCollector(config packet.Config, targetAccepter pmmime.VisitAcceptor) *SignatureCollector {
return &SignatureCollector{
target: targetAccepter,
config: config,
}
}
func getRawMimePart(rawdata io.Reader, boundary string) (io.Reader, io.Reader) {
b, _ := ioutil.ReadAll(rawdata)
tee := bytes.NewReader(b)
reader := bufio.NewReader(bytes.NewReader(b))
byteBoundary := []byte(boundary)
bodyBuffer := &bytes.Buffer{}
for {
line, _, err := reader.ReadLine()
if err != nil {
return tee, bytes.NewReader(bodyBuffer.Bytes())
}
if bytes.HasPrefix(line, byteBoundary) {
break
}
}
for {
line, _, err := reader.ReadLine()
if err != nil {
return tee, bytes.NewReader(bodyBuffer.Bytes())
}
if bytes.HasPrefix(line, byteBoundary) {
break
}
bodyBuffer.Write(line)
}
ioutil.ReadAll(reader)
return tee, bytes.NewReader(bodyBuffer.Bytes())
}
func getMultipartParts(r io.Reader, params map[string]string) (parts []io.Reader, headers []textproto.MIMEHeader, err error) {
mr := multipart.NewReader(r, params["boundary"])
parts = []io.Reader{}
@ -62,12 +101,23 @@ func getMultipartParts(r io.Reader, params map[string]string) (parts []io.Reader
return
}
func verifyMime(body io.Reader, bodyHeader textproto.MIMEHeader, signature io.Reader) (err error) {
rawData, err := ioutil.ReadAll(body)
if err != nil {
return err
}
decodedBodyStream := pmmime.DecodeContentEncoding(bytes.NewReader(rawData), bodyHeader.Get("Content-Transfer-Encoding"))
}
func (sc *SignatureCollector) Accept(part io.Reader, header textproto.MIMEHeader, hasPlainSibling bool, isFirst, isLast bool) (err error) {
parentMediaType, params, _ := mime.ParseMediaType(header.Get("Content-Type"))
if parentMediaType == "multipart/signed" {
newPart, rawBody := getRawMimePart(part, params["boundary"])
var multiparts []io.Reader
var multipartHeaders []textproto.MIMEHeader
if multiparts, multipartHeaders, err = getMultipartParts(part, params); err != nil {
if multiparts, multipartHeaders, err = getMultipartParts(newPart, params); err != nil {
return
} else {
hasPlainChild := false
@ -78,7 +128,9 @@ func (sc *SignatureCollector) Accept(part io.Reader, header textproto.MIMEHeader
}
}
if len(multiparts) != 2 {
sc.verified = notSigned
// Invalid multipart/signed format just pass along
ioutil.ReadAll(rawBody)
for i, p := range multiparts {
if err = sc.target.Accept(p, multipartHeaders[i], hasPlainChild, true, true); err != nil {
return
@ -86,13 +138,14 @@ func (sc *SignatureCollector) Accept(part io.Reader, header textproto.MIMEHeader
}
return
}
// actual multipart/signed format
err = sc.target.Accept(multiparts[0], multipartHeaders[0], hasPlainChild, true, true)
if err != nil {
return
}
partData, _ := ioutil.ReadAll(multiparts[1])
decodedPart := pmmime.DecodeContentEncoding(bytes.NewReader(partData), header.Get("Content-Transfer-Encoding"))
decodedPart := pmmime.DecodeContentEncoding(bytes.NewReader(partData), multipartHeaders[1].Get("Content-Transfer-Encoding"))
buffer, err := ioutil.ReadAll(decodedPart)
if err != nil {
return err
@ -102,7 +155,15 @@ func (sc *SignatureCollector) Accept(part io.Reader, header textproto.MIMEHeader
return err
}
sc.signature = string(buffer)
return err
_, err = openpgp.CheckArmoredDetachedSignature(sc.keyring, rawBody, bytes.NewReader(buffer), &sc.config)
if err != nil {
sc.verified = failed
} else {
sc.verified = ok
}
return nil
}
return
}
@ -116,12 +177,15 @@ func (ac SignatureCollector) GetSignature() string {
}
func ParseMIME(mimeBody string) (body *pmmime.BodyCollector, atts, attHeaders []string, err error) {
func (openpgp OpenPGP) ParseMIME(mimeBody string, verifierKey []byte) (body *pmmime.BodyCollector, atts, attHeaders []string, err error) {
mm, err := mail.ReadMessage(strings.NewReader(mimeBody))
if err != nil {
return
}
config := &packet.Config{DefaultCipher: packet.CipherAES256, Time: openpgp.getTimeGenerator() }
h := textproto.MIMEHeader(mm.Header)
mmBodyData, err := ioutil.ReadAll(mm.Body)
@ -130,7 +194,7 @@ func ParseMIME(mimeBody string) (body *pmmime.BodyCollector, atts, attHeaders []
bodyCollector := pmmime.NewBodyCollector(printAccepter)
attachmentsCollector := pmmime.NewAttachmentsCollector(bodyCollector)
mimeVisitor := pmmime.NewMimeVisitor(attachmentsCollector)
signatureCollector := NewSignatureCollector(mimeVisitor)
signatureCollector := NewSignatureCollector(config, mimeVisitor)
err = pmmime.VisitAll(bytes.NewReader(mmBodyData), h, signatureCollector)
body = bodyCollector
@ -142,6 +206,83 @@ func ParseMIME(mimeBody string) (body *pmmime.BodyCollector, atts, attHeaders []
/*
func CheckDetachedSignature(keyring KeyRing, signed, signature io.Reader, config *packet.Config) (signer *Entity, err error) {
var issuerKeyId uint64
var hashFunc crypto.Hash
var sigType packet.SignatureType
var keys []Key
var p packet.Packet
packets := packet.NewReader(signature)
for {
p, err = packets.Next()
if err == io.EOF {
return nil, errors.ErrUnknownIssuer
}
if err != nil {
return nil, err
}
switch sig := p.(type) {
case *packet.Signature:
if sig.IssuerKeyId == nil {
return nil, errors.StructuralError("signature doesn't have an issuer")
}
issuerKeyId = *sig.IssuerKeyId
hashFunc = sig.Hash
sigType = sig.SigType
case *packet.SignatureV3:
issuerKeyId = sig.IssuerKeyId
hashFunc = sig.Hash
sigType = sig.SigType
default:
return nil, errors.StructuralError("non signature packet found")
}
keys = keyring.KeysByIdUsage(issuerKeyId, packet.KeyFlagSign)
if len(keys) > 0 {
break
}
}
if len(keys) == 0 {
panic("unreachable")
}
h, wrappedHash, err := hashForSignature(hashFunc, sigType)
if err != nil {
return nil, err
}
if _, err := io.Copy(wrappedHash, signed); err != nil && err != io.EOF {
return nil, err
}
for _, key := range keys {
switch sig := p.(type) {
case *packet.Signature:
err = key.PublicKey.VerifySignature(h, sig)
if err == nil && sig.KeyExpired(config.Now()) {
err = errors.ErrSignatureExpired
}
case *packet.SignatureV3:
err = key.PublicKey.VerifySignatureV3(h, sig)
default:
panic("unreachable")
}
if err == errors.ErrSignatureExpired {
return key.Entity, err
}
if err == nil {
return key.Entity, nil
}
}
return nil, err
}
// define call back interface
type MIMECallbacks interface {
onBody(body string, mimetype string)
@ -149,6 +290,9 @@ type MIMECallbacks interface {
// Encrypted headers can be an attachment and thus be placed at the end of the mime structure
onEncryptedHeaders(headers string)
}
func (o *OpenPGP) DecryptMessageVerifyBinKeyPrivbinkeys(encryptedText string, veriferKey []byte, privateKeys []byte, passphrase string, verifyTime int64) (*DecryptSignedVerify, error) {
return o.decryptMessageVerifyAllBin(encryptedText, veriferKey, privateKeys, passphrase, verifyTime)
}
func (o *OpenPGP) decryptMIMEMessage(encryptedText string, verifierKey string, privateKeys []byte,
passphrase string, callbacks MIMECallbacks, verifyTime int64) (verifier int, err error) {