DKIM package for golang

go-dkim

DKIM package for Golang

GoDoc

Getting started

Install

 	go get github.com/toorop/go-dkim

Warning: you need to use Go 1.4.2-master or 1.4.3 (when it will be available) see https://github.com/golang/go/issues/10482 fro more info.

Sign email

import (
	dkim "github.com/toorop/go-dkim"
)

func main(){
	// email is the email to sign (byte slice)
	// privateKey the private key (pem encoded, byte slice )	
	options := dkim.NewSigOptions()
	options.PrivateKey = privateKey
	options.Domain = "mydomain.tld"
	options.Selector = "myselector"
	options.SignatureExpireIn = 3600
	options.BodyLength = 50
	options.Headers = []string{"from", "date", "mime-version", "received", "received"}
	options.AddSignatureTimestamp = true
	options.Canonicalization = "relaxed/relaxed"
	err := dkim.Sign(&email, options)
	// handle err..

	// And... that's it, 'email' is signed ! AmazingΒ© !!!
}

Verify

import (
	dkim "github.com/toorop/go-dkim"
)

func main(){
	// email is the email to verify (byte slice)
	status, err := Verify(&email)
	// handle status, err (see godoc for status)
}

Todo

  • handle z tag (copied header fields used for diagnostic use)
Owner
StΓ©phane Depierrepont
Go developer. Available as freelancer
StΓ©phane Depierrepont
Comments
  • Signing html body content

    Signing html body content

    When signing an email with html content, dkim will not verify with dkim=neutral (body hash did not verify). Switch body content to simple text, dkim will verify.

    Any ideas?

  • Expose and rename newDkimHeaderFromEmail

    Expose and rename newDkimHeaderFromEmail

    Closes Issue #18

    This MR does 3 main things:

    1. It rename newDkimHeaderFromEmail to GetHeader in order to publicly expose it
    2. It renames dkimHeader to DKIMHeader
    3. It unexports the RawForSign field from DKIMHeader, since this seems like a field that's only applicable internally

    I also added a couple rudimentary unit tests, but these aren't exhaustive since most of the code coverage is already done in Test_Validate

  • Add function to retrieve parsed DKIM header

    Add function to retrieve parsed DKIM header

    Problem

    I'm currently working on a mail server that reads in emails and does a number of security checks on them. One of the checks is the basic call to the Verify function, which works perfectly fine. However, I would also like to perform a DMARC-like check on the DKIM alignment to validate whether the From header domain corresponds to the same organizational domain as the domain in the d= header.

    From what I understand about this implementation, the Verify function will use the first DKIM-Signature unless it is overriden by another DKIM-Signature that has the same domain as the From header. So for the case of a single DKIM signature that is valid but with a different domain as the From header, I would like to bring attention to it.

    Suggested Solution

    In my mind, the easiest way for this is to make a function that take in the email byte slice and outputs an unvalidated dkimHeader struct. That way, I can first perform the DKIM validation as a whole, then if that succeeds use the parsed object for additional checks. Based in the code, this could probably be accomplished just be exposing newDkimHeaderFromEmail as a public function. Would you have any qualms with doing so?

    References

    • https://tools.ietf.org/html/rfc7489#section-3.1.1
  • do not replace \n to \r\n when \r\n\r\n exists

    do not replace \n to \r\n when \r\n\r\n exists

    when the \r\n\r\n exists on email, the getHeadersBody function will replace it to \r\r\n\r\r\n, this corrupt the mail, getHeadersBody will return ErrBadMailFormat error, but this error not handled by canonicalize, so getHeadersList panic

  • How to use go-dkim

    How to use go-dkim

    Hello,

    thank you for your work πŸ’―

    Can you please explain the usual way to use it in Go?

    If i look at email-packages, they construct structs as emails, but you sign a []byte.

    Whats now the usual packages / way to send this signed thing via system sendmail?

    I can generate a []byte often via SliceForSigning := email.Bytes() for example, but than i have the old email object and the new signed? []byte.

    Do you know a sample using any Go email package with go-dkim?


    Just a sample what i mean:

            // using "github.com/jordan-wright/email"
    
    	e := email.NewEmail()
    	e.From = "Me <[email protected]>"
    	e.To = []string{"[email protected]"}
    	e.Subject = "dkim test"
    	e.HTML = []byte("<h1>some HTML</h1>")
    
    	byteSlice, err = e.Bytes()
    
    	options := dkim.NewSigOptions()
    	options.PrivateKey = privKey
    	options.Domain = "domain.tld"
    	options.Selector = "selector"
    	options.SignatureExpireIn = 3600
    	options.BodyLength = uint(len([]byte("<h1>some HTML</h1>")))
    	options.Headers = []string{"from", "date", "mime-version", "received", "received"}
    	options.AddSignatureTimestamp = true
    	options.Canonicalization = "relaxed/relaxed"
    
    	err = dkim.Sign(&byteSlice, options)
    
            // how to use signed []byte?
    
    	e.Send("smtp.domain.tld:587", smtp.PlainAuth("", "name", "password", "smtp.domain.tld"))
    

    Thank you

  • unit test fails

    unit test fails

    go version go1.9.7 linux/amd64

    git commit hash - 83672023c79e6b352bf9d4908e6c060c7a24323c

    [vodolaz095@tractor go-dkim]$ go test -v
    === RUN   Test_NewSigOptions
    --- PASS: Test_NewSigOptions (0.00s)
    === RUN   Test_SignConfig
    --- PASS: Test_SignConfig (0.01s)
    === RUN   Test_canonicalize
    --- PASS: Test_canonicalize (0.00s)
    === RUN   Test_Sign
    --- PASS: Test_Sign (0.01s)
    === RUN   Test_Verify
    --- FAIL: Test_Verify (0.47s)
    	dkim_test.go:350: 
    			Error Trace:	dkim_test.go:350
    			Error:      	Not equal: 
    			            	expected: &errors.errorString{s:"body hash did not verify"}
    			            	actual  : &errors.errorString{s:"no key for verify"}
    			            	
    			            	Diff:
    			            	--- Expected
    			            	+++ Actual
    			            	@@ -1,2 +1,2 @@
    			            	-(*errors.errorString)(body hash did not verify)
    			            	+(*errors.errorString)(no key for verify)
    			            	 
    			Test:       	Test_Verify
    	dkim_test.go:351: 
    			Error Trace:	dkim_test.go:351
    			Error:      	Not equal: 
    			            	expected: 6
    			            	actual  : 2
    			Test:       	Test_Verify
    	dkim_test.go:375: 
    			Error Trace:	dkim_test.go:375
    			Error:      	Received unexpected error:
    			            	no key for verify
    			Test:       	Test_Verify
    	dkim_test.go:376: 
    			Error Trace:	dkim_test.go:376
    			Error:      	Not equal: 
    			            	expected: 1
    			            	actual  : 2
    			Test:       	Test_Verify
    	dkim_test.go:381: 
    			Error Trace:	dkim_test.go:381
    			Error:      	Received unexpected error:
    			            	no key for verify
    			Test:       	Test_Verify
    	dkim_test.go:382: 
    			Error Trace:	dkim_test.go:382
    			Error:      	Not equal: 
    			            	expected: 1
    			            	actual  : 2
    			Test:       	Test_Verify
    FAIL
    exit status 1
    FAIL	github.com/toorop/go-dkim	0.492s
    
  • PKCS8 decode

    PKCS8 decode

    We've a setup with mixed keys (PKCS1 and PKCS8). Currently we decode the keys and re-encode the keys into PKCS1 before using the pkg.

    This is a unnecessary decoding/encoding work when the pkg also accepts PKCS8 keys :)

  • Replace LF with CRLF

    Replace LF with CRLF

    Emails fail validation due to "bad mail format", which is caused by loss of CRLFs somewhere in the data pipeline when a raw email is downloaded for testing this library. This PR attempts to fix this problem by replacing all LFs with CRLFs as was noted in the TODO tag on line 537 of dkim.go

    While I don't completely understand where in the pipeline the problem is occurring, I am opening this PR to bring attention to this problem and begin solving it with your help.

  • Prevent panic on type conversion

    Prevent panic on type conversion

    Hello, thanks for your package! I'm using it in spam filter service. On one of mail servers, my service periodically panics:

    Dec  2 17:36:42 e-mail: panic: interface conversion: interface {} is nil, not *rsa.PublicKey
    Dec  2 17:36:42 e-mail: goroutine 55532 [running]:
    Dec  2 17:36:42 e-mail: github.com/toorop/go-dkim.newPubKeyFromDnsTxt(0xc42042f222, 0x4, 0xc42042f205, 0x10, 0x3, 0x484d1b, 0xc420014070, 0xc420014000)
    Dec  2 17:36:42 e-mail: /go/src/github.com/toorop/go-dkim/pubKeyRep.go:95 +0x10fa
    Dec  2 17:36:42 e-mail: github.com/toorop/go-dkim.Verify(0xc42032fc38, 0xc420076230, 0x2, 0xc42056a990)
    Dec  2 17:36:42 e-mail: /go/src/github.com/toorop/go-dkim/dkim.go:214 +0x148
    Dec  2 17:36:42 e-mail: main.verifyDKIM(0xc420516000, 0x4944, 0x5c30, 0x0, 0x0, 0x5874e0)
    
  • parseDkHeader() crashes when flag does not have

    parseDkHeader() crashes when flag does not have "=" delimeter

    parseDkHeader() assumes that flagData contains 2 elements after strings.SplitN()

    panic: runtime error: index out of range [recovered] panic: runtime error: index out of range

    goroutine 5 [running]: testing.funcΒ·006() /usr/local/go/src/testing/testing.go:441 +0x181 github.com/toorop/go-dkim.parseDkHeader(0xc208dba000, 0x238, 0xc208d9fb00, 0x0, 0x0) /home/arlyn/trident/trident/vendor/src/github.com/toorop/go-dkim/dkimHeader.go:326 +0x1e79 github.com/toorop/go-dkim.newDkimHeaderFromEmail(0xc208d95c60, 0x919df0, 0x0, 0x0) /home/arlyn/trident/trident/vendor/src/github.com/toorop/go-dkim/dkimHeader.go:272 +0x7bd github.com/toorop/go-dkim.Verify(0xc208d95c60, 0xc208da2000, 0x0, 0x0) /home/arlyn/trident/trident/vendor/src/github.com/toorop/go-dkim/dkim.go:205 +0x4e hegoa/filters/features.ruleDKIMCheck(0x919750, 0x9, 0x9ca070, 0x4, 0x0, 0x0, 0x0, 0xc208d317c0, 0x7f4352127f40, 0xc208d88160, ...) /home/arlyn/trident/trident/src/hegoa/filters/features/rules.go:759 +0xe5 hegoa/filters/features.funcΒ·003(0x7f4352127f40, 0xc208d88160, 0xa) /home/arlyn/trident/trident/src/hegoa/filters/features/rules.go:158 +0x3af common/mimedec.DepthMatchAll(0x7f4352127f40, 0xc208d88160, 0xc208e87c58, 0x0, 0x0, 0x0) /home/arlyn/trident/trident/src/common/mimedec/match.go:91 +0xd6 hegoa/filters/features.runRules(0x7f4352127cc0, 0xc20811c020, 0xc2080e6000, 0xc208d317c0, 0x0, 0x0) /home/arlyn/trident/trident/src/hegoa/filters/features/rules.go:163 +0x246 hegoa/filters/features.(*featureExtractor).Filter(0xc20811c000, 0xc208d2f040, 0xc208d2f040, 0x0, 0x0) /home/arlyn/trident/trident/src/hegoa/filters/features/features.go:40 +0xb5 hegoa/filters/features.TestShoalFile(0xc2080901b0) /home/arlyn/trident/trident/src/hegoa/filters/features/features_test.go:139 +0x6e5 testing.tRunner(0xc2080901b0, 0x1255a40) /usr/local/go/src/testing/testing.go:447 +0xbf created by testing.RunTests /usr/local/go/src/testing/testing.go:555 +0xa8b

  • Always using the relaxed body canonicalization is invalid per DKIM - RFC 6376

    Always using the relaxed body canonicalization is invalid per DKIM - RFC 6376

    https://github.com/toorop/go-dkim/blob/e1cd1a0a520837806993afa1f6fd4e430010f6d7/dkim.go#L229 is always executed when validating DKIM with this module.

    That executes https://github.com/toorop/go-dkim/blob/e1cd1a0a520837806993afa1f6fd4e430010f6d7/dkim.go#L353 meaning that relaxed canonicalization is always executed. The protocol specifies that simple/simple is the default.

    That is not valid per RFC 6376 because the DKIM header does not need to contain the c= tag and simple/simple is the default.

    c= Message canonicalization (plain-text; OPTIONAL, default is
          "simple/simple").  This tag informs the Verifier of the type of
          canonicalization used to prepare the message for signing.  It
          consists of two names separated by a "slash" (%d47) character,
          corresponding to the header and body canonicalization algorithms,
          respectively.  These algorithms are described in [Section 3.4](https://www.rfc-editor.org/rfc/rfc6376#section-3.4).  If
          only one algorithm is named, that algorithm is used for the header
          and "simple" is used for the body.  For example, "c=relaxed" is
          treated the same as "c=relaxed/simple".
    
  • support ed25519-sha256

    support ed25519-sha256

    I'm using this library in my project and I'm very pleased with it.

    I was wondering if there are any plans to support the ed25519-sha256 signing algorithm, and/or if there is any interest in a PR that adds support?

  • Body length 0 causes incorrect sig for validate

    Body length 0 causes incorrect sig for validate

    When verifying a signature, the code treats a body length of 0 as the same as no body length specified at all. What should actually happen is that if there is a body length of 0, then the message body is not signed and you generate a signature over no data. If there's no body length specified, then the code should sign over the entire message (this does happen now).

  • Relaxed body and empty message doesn't validate

    Relaxed body and empty message doesn't validate

    Best I can tell from reading the RFC and your code, you're processing relaxed bodies correctly. But I have verified with three different services, including Gmail and Yahoo Mail, that messages sent by them with empty bodies do not verify. The fix is easy (I don't have a PR because I've modified the code a bunch for other reasons). In dkim.go, line 361, wrap that append line with a "if len(body) > 0" conditional.

    It's easy to test. In Gmail, send yourself a blank message. Then validate its DKIM sig.

Related tags
Golang package that generates clean, responsive HTML e-mails for sending transactional mail
Golang package that generates clean, responsive HTML e-mails for sending transactional mail

Hermes Hermes is the Go port of the great mailgen engine for Node.js. Check their work, it's awesome! It's a package that generates clean, responsive

Dec 28, 2022
MIME mail encoding and decoding package for Go

enmime enmime is a MIME encoding and decoding library for Go, focused on generating and parsing MIME encoded emails. It is being developed in tandem w

Nov 30, 2022
POP-3 client package for Go.

GOP-3 (Go + POP-3) is a POP-3 client for Go. It has experimental purpose and it is still under development. RFC 1939 document has been followed while developing package.

Dec 25, 2021
Hxgomail - Gomail - a simple and efficient package to send emails

Gomail Introduction Gomail is a simple and efficient package to send emails. It

Jan 4, 2022
Inline styling for html mail in golang

go-premailer Inline styling for HTML mail in golang Document install go get github.com/vanng822/go-premailer/premailer Example import ( "fmt" "gith

Nov 30, 2022
The Official Twilio SendGrid Led, Community Driven Golang API Library
The Official Twilio SendGrid Led, Community Driven Golang API Library

NEW: Subscribe to email notifications for releases and breaking changes. The default branch name for this repository has been changed to main as of 07

Dec 15, 2022
An email MIME artist for golang

Marcel is a tool to generate IETF compliant emails in raw MIME format. I mainly use this for generating emails with attachments and sending them via amazon SES. If that's what you're doing too, you may want notifications

Nov 7, 2022
Go Mail - A cross platform mail driver for GoLang.
Go Mail  - A cross platform mail driver for GoLang.

Go Mail aims to unify multiple popular mail API's (SparkPost, MailGun & SendGrid) into a singular easy to use interface. Email sending is seriously simple and great for allowing the developer to choose what platform they use.

Dec 16, 2022
EMail Searcher By Golang
EMail Searcher By Golang

GiveMeMail β–„β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–“ β–ˆβ–ˆβ–’ β–ˆβ–ˆβ–“ β–“β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–„ β–„β–ˆβ–ˆβ–ˆβ–“β–“β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–„ β–„β–ˆβ–ˆβ–ˆβ–“ β–ˆβ–ˆ β–ˆβ–ˆβ–“ β–ˆβ–ˆβ–“ β–ˆβ–ˆβ–’ β–€β–ˆβ–’ β–“β–ˆβ–ˆβ–’ β–“β–ˆβ–ˆβ–‘ β–ˆβ–’ β–“β–ˆ β–€ β–“β–ˆβ–ˆβ–’β–€β–ˆβ–€ β–ˆβ–ˆβ–’β–“β–ˆ

Dec 4, 2021
go-pst is a library for reading PST files (written in Go/Golang).
go-pst is a library for reading PST files (written in Go/Golang).

go-pst A library for reading PST files (written in Go/Golang). Introduction go-pst is a library for reading PST files (written in Go/Golang). The PFF

Dec 29, 2022
golang honeypot smtp server
golang honeypot smtp server

honeygogo-smtp standalone honeypot A lightweight SMTP honeypot server written in Go, leveraging go-smtp. A stand alone version of a module from honeyg

May 4, 2022
πŸ“§ Example of sending mail via SendGrid in Golang.

?? go-sendgrid-example Example of sending mail via SendGrid in Golang. Get it started $ make setup # Edit environment variables $ vim ./env/local.env

Jan 11, 2022
An email service written in Golang
An email service written in Golang

furion An email service written in Go. Architecture Diagram

Dec 19, 2021
Email - Emailing with limitator for golang

email Emailing with optional limiter. It will send no more then limiterMax email

Jan 3, 2022
Golang library for sending email using gmail credentials

library for sending email using gmail credentials

Jan 22, 2022
A Go (golang) package that enhances the standard database/sql package by providing powerful data retrieval methods as well as DB-agnostic query building capabilities.

ozzo-dbx Summary Description Requirements Installation Supported Databases Getting Started Connecting to Database Executing Queries Binding Parameters

Dec 31, 2022
Go Package Manager (gopm) is a package manager and build tool for Go.

?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? In favor of Go Modules Proxy since Go 1.11, this pr

Dec 14, 2022
Package set is a small wrapper around the official reflect package that facilitates loose type conversion and assignment into native Go types.

Package set is a small wrapper around the official reflect package that facilitates loose type conversion and assignment into native Go types. Read th

Dec 27, 2022
Go package providing simple database and server interfaces for the CSV files produced by the sfomuseum/go-libraryofcongress package
Go package providing simple database and server interfaces for the CSV files produced by the sfomuseum/go-libraryofcongress package

go-libraryofcongress-database Go package providing simple database and server interfaces for the CSV files produced by the sfomuseum/go-libraryofcongr

Oct 29, 2021