-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SNS signature verification #567
Comments
Hello @robbiet480, thank you for contacting us. Is your body an expected pem cert? Print out the URL to ensure that it is also correct. Looking at the RSA VerifyPKCS1v15 function, there are only two spots that returns that error. If the public key is incorrect in size or if the verification fails. If it has failed the verification, then more digging needs to be done. |
Hey @xibz I confirmed the URL is correct and when I downloaded the PEM I was able to successfully open it with OSX's Keychain Access. I confirmed that the PEM that Go downloads exactly matches what I download with Chrome. The only difference is absence of a newline character at the very end of the file, but I don't believe that would cause an issue. |
When looking at the algorithm map in x509, I noticed that |
The newline could break it, if it is included in the verifying. Any difference whatsoever in signed/signature or public key will break the verification. The |
@xibz I did just test it with and without an extra newline but nothing changed :(. I also had Go write out the exact PEM file it's receiving and diff'ed it against the one downloaded via Chrome and found no differences. I don't have a handy PHP setup anywhere, so I'll test the byte array suggestion in Javascript and get back to you shortly. |
@xibz Okay, I tested with both PHP and Javascript. I built some really simple Go tests to confirm everything that's coming in is the same when it comes out (just in case there was something weird happening like when filling the struct). All of the tests are passing for me. I don't see this being an issue in any of the above code, so everything points to something different or wrong with the way Go is doing the certificate check. I'm considering ripping out all the Go crypto code and implementing OpenSSL directly using one of the available libraries. Let me know if you have any other pointers on how to proceed. |
@robbiet480, interesting that Golang is behaving that way. I am going to do some small test and see if I can figure something out. I really would like to prevent needing to use external libraries. |
@xibz I may have fixed it actually. Testing and retesting right now |
@robbiet480 Awesome! I am really curious to what the issue was. Please let us know! |
I think that Also note I changed from manually coding in the string generation to a method more like the PHP/JS libraries. Here's the code I have, let me know if I got it right: func (sns *SNSData) verifySNS() (bool, error) {
var buffer bytes.Buffer
signableKeys := []string{"Message", "MessageId", "Subject", "Timestamp", "TopicArn", "Type"}
for _, key := range signableKeys {
r := reflect.ValueOf(sns)
f := reflect.Indirect(r).FieldByName(key)
keyString := f.String()
if keyString != "" {
buffer.WriteString(key + "\n")
buffer.WriteString(keyString + "\n")
}
}
base64decodedsignature, err := base64.StdEncoding.DecodeString(sns.Signature)
if err != nil {
log.Errorln("Base64 decoding error!", err)
}
resp, err := http.Get(sns.SigningCertURL)
if err != nil {
log.Errorln("HTTP GET error!", err)
}
defer resp.Body.Close()
// print("URL\n", sns.SigningCertURL)
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Errorln("IOUtil error!", err)
}
p, _ := pem.Decode(body)
cert, err := x509.ParseCertificate(p.Bytes)
if err != nil {
log.Errorln("Certificate parsing error!", err)
}
// This returns false for some reason
checkErr := cert.CheckSignature(x509.SHA1WithRSA, base64decodedsignature, buffer.Bytes())
if checkErr != nil {
log.Println("CheckSignature error!", checkErr)
}
pub := cert.PublicKey.(*rsa.PublicKey)
h := sha1.New()
h.Write(buffer.Bytes())
digest := h.Sum(nil)
finalVerifyErr := rsa.VerifyPKCS1v15(pub, crypto.SHA1, digest, base64decodedsignature)
if finalVerifyErr != nil {
log.Println("verify:", finalVerifyErr)
return false, finalVerifyErr
} else {
return true, nil
}
} |
Nvm, found it. Change this to this. cert.CheckSignature(x509.SHA1WithRSA, buffer.Bytes(), base64decodedsignature) The |
@xibz Works for me! Thanks so much for helping out with them. I would offer to submit cleaned up code to do verification but I'm unsure where this would fit. Otherwise, i'll just build this into an external library which i'll release. |
@robbiet480, my pleasure. Yea, I don't know if it would make sense to place this in the SDK. It may be a good idea to publish this as an external library since I can see people possibly wanting to just verify the request and not needing the SDK. Thank you for posting detailed attempts and solutions. I can see people wanting to know how to do this! |
Hello,
I, and at least two others, have been unable to do proper SNS HTTP(S) signature verification. I have pasted my most recent attempt below. Currently, I and the others get the following error when attempting validation:
crypto/rsa: verification error
which is a generic Go RSA error (found here)I am hoping that either A) someone can figure out what's wrong with the below (or any of the above implementations) and let me know so I can get it working, at which point I would be happy to clean up and then submit a PR for or B) SNS signature validation is added as a feature in aws-sdk-go (or an external library like the below linked JS and PHP versions).
Here's some documentation to assist anyone interested in helping:
Thanks so much!
The text was updated successfully, but these errors were encountered: