Commit 3b7e47cc authored by Lukas Matt's avatar Lukas Matt

Fix signature verification by using xml order

fixes ganggo#1
parent da96e258
...@@ -50,11 +50,13 @@ type Entity struct { ...@@ -50,11 +50,13 @@ type Entity struct {
Data interface{} `xml:"-"` Data interface{} `xml:"-"`
} }
type Time struct { type Time string
time.Time
func (m Message) Signature() string {
return m.Sig.Sig
} }
func (m Message) SignatureText() []string { func (m Message) SignatureText(order string) []string {
return []string{ return []string{
m.Data.Data, m.Data.Data,
base64.StdEncoding.EncodeToString([]byte(m.Data.Type)), base64.StdEncoding.EncodeToString([]byte(m.Data.Type)),
...@@ -63,20 +65,17 @@ func (m Message) SignatureText() []string { ...@@ -63,20 +65,17 @@ func (m Message) SignatureText() []string {
} }
} }
func (t *Time) MarshalXML(e *xml.Encoder, start xml.StartElement) error { func (t *Time) New(newTime time.Time) *Time {
e.EncodeElement(t.Format(TIME_FORMAT), start) *t = Time(newTime.UTC().Format(TIME_FORMAT))
return nil return t
} }
func (t *Time) UnmarshalXML(decoder *xml.Decoder, start xml.StartElement) error { func (t Time) Time() (time.Time, error) {
var value string return time.Parse(TIME_FORMAT, string(t))
decoder.DecodeElement(&value, &start) }
parse, err := time.Parse(TIME_FORMAT, value)
if err != nil { func (t Time) String() string {
return err return string(t)
}
*t = Time{parse}
return nil
} }
func (e *Entity) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { func (e *Entity) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
......
...@@ -138,9 +138,8 @@ func TestEntitiesTimeMarshalAndUnmarshal(t *testing.T) { ...@@ -138,9 +138,8 @@ func TestEntitiesTimeMarshalAndUnmarshal(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("Some error occured while parsing: %v", err) t.Errorf("Some error occured while parsing: %v", err)
} }
if origTime.CreatedAt.Time.Format(TIME_FORMAT) != time { if origTime.CreatedAt.String() != time {
t.Errorf("Expected to be '%s', got '%s'", t.Errorf("Expected to be '%s', got '%s'", origTime.CreatedAt.String())
origTime.CreatedAt.Time.Format(TIME_FORMAT))
} }
result, err := xml.Marshal(origTime) result, err := xml.Marshal(origTime)
...@@ -151,8 +150,10 @@ func TestEntitiesTimeMarshalAndUnmarshal(t *testing.T) { ...@@ -151,8 +150,10 @@ func TestEntitiesTimeMarshalAndUnmarshal(t *testing.T) {
t.Errorf("Expected to be '%s', got '%s'", result, rawXml) t.Errorf("Expected to be '%s', got '%s'", result, rawXml)
} }
err = xml.Unmarshal([]byte("<time><CreatedAt></CreatedAt></time>"), &origTime) // XXX the application server uses time.Now if this happens
if err == nil { // we should change that and let the library decide what is best
t.Errorf("Expected an error, got nil") //err = xml.Unmarshal([]byte("<time><CreatedAt></CreatedAt></time>"), &origTime)
} //if err == nil {
// t.Errorf("Expected an error, got nil")
//}
} }
...@@ -29,10 +29,17 @@ type EntityComment struct { ...@@ -29,10 +29,17 @@ type EntityComment struct {
AuthorSignature string `xml:"author_signature"` AuthorSignature string `xml:"author_signature"`
} }
func (e EntityComment) SignatureText() []string { func (e EntityComment) Signature() string {
return e.AuthorSignature
}
func (e EntityComment) SignatureText(order string) (signatureOrder []string) {
if order != "" {
return ExractSignatureText(order, e)
}
return []string{ return []string{
e.Author, e.Author,
e.CreatedAt.Format(TIME_FORMAT), e.CreatedAt.String(),
e.Guid, e.Guid,
e.ParentGuid, e.ParentGuid,
e.Text, e.Text,
......
...@@ -26,10 +26,10 @@ func TestCommentAppendSignature(t *testing.T) { ...@@ -26,10 +26,10 @@ func TestCommentAppendSignature(t *testing.T) {
comment := EntityComment{ comment := EntityComment{
Author: "author@localhost", Author: "author@localhost",
Guid: "1234", Guid: "1234",
CreatedAt: Time{time.Now()},
ParentGuid: "4321", ParentGuid: "4321",
Text: "hello world", Text: "hello world",
} }
comment.CreatedAt.New(time.Now())
if comment.AuthorSignature != "" { if comment.AuthorSignature != "" {
t.Errorf("Expected to be empty, got %s", comment.AuthorSignature) t.Errorf("Expected to be empty, got %s", comment.AuthorSignature)
......
...@@ -32,7 +32,15 @@ type EntityLike struct { ...@@ -32,7 +32,15 @@ type EntityLike struct {
SignatureOrder string `xml:"-"` SignatureOrder string `xml:"-"`
} }
func (e EntityLike) SignatureText() []string { func (e EntityLike) Signature() string {
return e.AuthorSignature
}
func (e EntityLike) SignatureText(order string) []string {
if order != "" {
return ExractSignatureText(order, e)
}
positive := "false" positive := "false"
if e.Positive { if e.Positive {
positive = "true" positive = "true"
......
...@@ -23,8 +23,47 @@ import ( ...@@ -23,8 +23,47 @@ import (
"crypto/x509" "crypto/x509"
"encoding/pem" "encoding/pem"
"errors" "errors"
"reflect"
"strings"
) )
func ExractSignatureText(order string, entity interface{}) (signatureOrder []string) {
orderArr := strings.Split(order, " ")
typeOf := reflect.TypeOf(entity)
var mappingFields = map[string]int{}
for i := 0; i < typeOf.NumField(); i++ {
field := typeOf.Field(i)
xmlTag := field.Tag.Get("xml")
if xmlTag != "" {
xmlOpts := strings.Split(xmlTag, ",")
if len(xmlOpts) > 0 && strings.Contains(order, xmlOpts[0]) {
mappingFields[xmlOpts[0]] = i
}
}
}
valueOf := reflect.ValueOf(entity)
for _, orderElem := range orderArr {
if i, ok := mappingFields[orderElem]; ok {
if value, ok := valueOf.Field(i).Interface().(Time); ok {
signatureOrder = append(signatureOrder, string(value))
}
if value, ok := valueOf.Field(i).Interface().(string); ok {
signatureOrder = append(signatureOrder, value)
}
if value, ok := valueOf.Field(i).Interface().(bool); ok {
valueBool := "false"
if value {
valueBool = "true"
}
signatureOrder = append(signatureOrder, valueBool)
}
}
}
return
}
func ParseRSAPublicKey(decodedKey []byte) (*rsa.PublicKey, error) { func ParseRSAPublicKey(decodedKey []byte) (*rsa.PublicKey, error) {
block, _ := pem.Decode(decodedKey) block, _ := pem.Decode(decodedKey)
if block == nil { if block == nil {
......
...@@ -64,11 +64,7 @@ func SetLogger(writer LogWriter) { ...@@ -64,11 +64,7 @@ func SetLogger(writer LogWriter) {
} }
func (l Logger) Info(values... interface{}) { func (l Logger) Info(values... interface{}) {
values = append(values, []interface{}{""}) l.Println(l.Prefix, values, LOG_C_RESET)
copy(values[1:], values[0:])
values[0] = l.Prefix
values = append(values, LOG_C_RESET)
l.Println(values)
} }
func (l Logger) Error(values... interface{}) { func (l Logger) Error(values... interface{}) {
......
...@@ -24,8 +24,7 @@ import ( ...@@ -24,8 +24,7 @@ import (
"strings" "strings"
) )
func ParseDecryptedRequest(entityXML []byte) (entity Entity, err error) { func ParseDecryptedRequest(entityXML []byte) (message Message, entity Entity, err error) {
var message Message
err = xml.Unmarshal(entityXML, &message) err = xml.Unmarshal(entityXML, &message)
if err != nil { if err != nil {
logger.Error(err) logger.Error(err)
...@@ -48,18 +47,21 @@ func ParseDecryptedRequest(entityXML []byte) (entity Entity, err error) { ...@@ -48,18 +47,21 @@ func ParseDecryptedRequest(entityXML []byte) (entity Entity, err error) {
return return
} }
message.Sig.KeyId = string(keyId) message.Sig.KeyId = string(keyId)
logger.Info("Entity sender", message.Sig.KeyId)
data, err := base64.URLEncoding.DecodeString(message.Data.Data) data, err := base64.URLEncoding.DecodeString(message.Data.Data)
if err != nil { if err != nil {
logger.Error(err) logger.Error(err)
return return
} }
logger.Info("Entity raw", string(data))
entity.SignatureOrder, err = FetchEntityOrder(data) entity.SignatureOrder, err = FetchEntityOrder(data)
if err != nil { if err != nil {
logger.Error(err) logger.Error(err)
return return
} }
logger.Info("Entity order", entity.SignatureOrder)
err = xml.Unmarshal(data, &entity) err = xml.Unmarshal(data, &entity)
if err != nil { if err != nil {
...@@ -69,7 +71,7 @@ func ParseDecryptedRequest(entityXML []byte) (entity Entity, err error) { ...@@ -69,7 +71,7 @@ func ParseDecryptedRequest(entityXML []byte) (entity Entity, err error) {
return return
} }
func ParseEncryptedRequest(wrapper AesWrapper, privKey *rsa.PrivateKey) (entity Entity, err error) { func ParseEncryptedRequest(wrapper AesWrapper, privKey *rsa.PrivateKey) (message Message, entity Entity, err error) {
entityXML, err := wrapper.Decrypt(privKey) entityXML, err := wrapper.Decrypt(privKey)
if err != nil { if err != nil {
logger.Error(err) logger.Error(err)
......
...@@ -22,17 +22,17 @@ import "testing" ...@@ -22,17 +22,17 @@ import "testing"
func TestParseDecryptedRequest(t *testing.T) { func TestParseDecryptedRequest(t *testing.T) {
var xml = []byte(`<?xml version="1.0" encoding="UTF-8"?><me:env xmlns:me="http://salmon-protocol.org/ns/magic-env"><me:data type="application/xml">PHN0YXR1c19tZXNzYWdlPgogIDxhdXRob3I-ZGlhc3BvcmFfMm5kQGxvY2FsaG9zdDozMDAxPC9hdXRob3I-CiAgPGd1aWQ-ZmUyZDJhODA1MzQ4MDEzNWQwOGY1Mjk2ZjJlNzQ0N2I8L2d1aWQ-CiAgPGNyZWF0ZWRfYXQ-MjAxNy0wNy0yNVQwOToyNDozM1o8L2NyZWF0ZWRfYXQ-CiAgPHByb3ZpZGVyX2Rpc3BsYXlfbmFtZS8-CiAgPHRleHQ-cGluZzwvdGV4dD4KICA8cHVibGljPmZhbHNlPC9wdWJsaWM-Cjwvc3RhdHVzX21lc3NhZ2U-</me:data><me:encoding>base64url</me:encoding><me:alg>RSA-SHA256</me:alg><me:sig key_id="ZGlhc3BvcmFfMm5kQGxvY2FsaG9zdDozMDAx">NbuD4kERZzXPFRORH4NOcr7EAij-dWKTCG0eBBGZObN3Aic0lMAZ_rLU7o6PLOH9Q6p6dyneYjUjSu07vtI5Jy_N2XQpKUni3fUWxfDNgfMo26XKmxdJ5S2Gp1ux1ToO3FY9RByTZw5HZRpOBAfRSgttTgiY5_Yu5D-BLcEm_94R6FMWRniQXrMAt8hU9qCNSuVQlUKtuuy8qJXu6Z21VhI9lAT7wIALlR9UwIgz0e6UG9S9sU95f_38co0ibD1KbQpBd8c_lu5vCVIqlEe_Fa_xYZupMLaU8De-wzoBpBgqR65mRtUQTu2jP-Qxa3aXrANHxweIbnYfpZ5QcNA50hfyVJJSolczDSlDljTunEmHmWNaS3J7waEQsIDFATPFy6H5leRPpSzebXYca4T-EiapPP-mn41Vs3VKIdUXOHus_HcTPWRVT-Vr-yt7byFYEanb5b5lQ_IHcI0oyqX7RrVJid6UsBtwxwkX0FSc1cZgLhBQUgxBsUh5MNte-WZJv_6c9rHyNsH3rn9YEZp431P9GCe8gNdLY9bFQ1pYS9BxOAS2enu3yVpWpWRechiR7D__HC4-Hw2MHfSSmBQTxq5oO01_efEHB8XxWF85XYNT6_icXf3ZsTxkURT9HlHapkFwL7TlO5gPUZZVJt9f6kn9HoGQ56MX2n46KdKKid8=</me:sig></me:env>`) var xml = []byte(`<?xml version="1.0" encoding="UTF-8"?><me:env xmlns:me="http://salmon-protocol.org/ns/magic-env"><me:data type="application/xml">PHN0YXR1c19tZXNzYWdlPgogIDxhdXRob3I-ZGlhc3BvcmFfMm5kQGxvY2FsaG9zdDozMDAxPC9hdXRob3I-CiAgPGd1aWQ-ZmUyZDJhODA1MzQ4MDEzNWQwOGY1Mjk2ZjJlNzQ0N2I8L2d1aWQ-CiAgPGNyZWF0ZWRfYXQ-MjAxNy0wNy0yNVQwOToyNDozM1o8L2NyZWF0ZWRfYXQ-CiAgPHByb3ZpZGVyX2Rpc3BsYXlfbmFtZS8-CiAgPHRleHQ-cGluZzwvdGV4dD4KICA8cHVibGljPmZhbHNlPC9wdWJsaWM-Cjwvc3RhdHVzX21lc3NhZ2U-</me:data><me:encoding>base64url</me:encoding><me:alg>RSA-SHA256</me:alg><me:sig key_id="ZGlhc3BvcmFfMm5kQGxvY2FsaG9zdDozMDAx">NbuD4kERZzXPFRORH4NOcr7EAij-dWKTCG0eBBGZObN3Aic0lMAZ_rLU7o6PLOH9Q6p6dyneYjUjSu07vtI5Jy_N2XQpKUni3fUWxfDNgfMo26XKmxdJ5S2Gp1ux1ToO3FY9RByTZw5HZRpOBAfRSgttTgiY5_Yu5D-BLcEm_94R6FMWRniQXrMAt8hU9qCNSuVQlUKtuuy8qJXu6Z21VhI9lAT7wIALlR9UwIgz0e6UG9S9sU95f_38co0ibD1KbQpBd8c_lu5vCVIqlEe_Fa_xYZupMLaU8De-wzoBpBgqR65mRtUQTu2jP-Qxa3aXrANHxweIbnYfpZ5QcNA50hfyVJJSolczDSlDljTunEmHmWNaS3J7waEQsIDFATPFy6H5leRPpSzebXYca4T-EiapPP-mn41Vs3VKIdUXOHus_HcTPWRVT-Vr-yt7byFYEanb5b5lQ_IHcI0oyqX7RrVJid6UsBtwxwkX0FSc1cZgLhBQUgxBsUh5MNte-WZJv_6c9rHyNsH3rn9YEZp431P9GCe8gNdLY9bFQ1pYS9BxOAS2enu3yVpWpWRechiR7D__HC4-Hw2MHfSSmBQTxq5oO01_efEHB8XxWF85XYNT6_icXf3ZsTxkURT9HlHapkFwL7TlO5gPUZZVJt9f6kn9HoGQ56MX2n46KdKKid8=</me:sig></me:env>`)
entity, err := ParseDecryptedRequest([]byte("")) _, entity, err := ParseDecryptedRequest([]byte(""))
if err == nil { if err == nil {
t.Errorf("Expected to be an error, got nil") t.Errorf("Expected to be an error, got nil")
} }
entity, err = ParseDecryptedRequest([]byte("<broken></broken")) _, entity, err = ParseDecryptedRequest([]byte("<broken></broken"))
if err == nil { if err == nil {
t.Errorf("Expected to be an error, got nil") t.Errorf("Expected to be an error, got nil")
} }
entity, err = ParseDecryptedRequest(xml) _, entity, err = ParseDecryptedRequest(xml)
if err != nil { if err != nil {
t.Errorf("Some error occured while parsing: %v", err) t.Errorf("Some error occured while parsing: %v", err)
} }
...@@ -51,7 +51,7 @@ func TestParseEncryptedRequest(t *testing.T) { ...@@ -51,7 +51,7 @@ func TestParseEncryptedRequest(t *testing.T) {
t.Errorf("Some error occured while parsing: %v", err) t.Errorf("Some error occured while parsing: %v", err)
} }
entity, err := ParseEncryptedRequest(wrapper, privKey) _, entity, err := ParseEncryptedRequest(wrapper, privKey)
if err != nil { if err != nil {
t.Errorf("Some error occured while parsing: %v", err) t.Errorf("Some error occured while parsing: %v", err)
} }
...@@ -60,14 +60,14 @@ func TestParseEncryptedRequest(t *testing.T) { ...@@ -60,14 +60,14 @@ func TestParseEncryptedRequest(t *testing.T) {
w := wrapper w := wrapper
w.AesKey = "" w.AesKey = ""
_, err = ParseEncryptedRequest(w, privKey) _, _, err = ParseEncryptedRequest(w, privKey)
if err == nil { if err == nil {
t.Errorf("Expected to be an error, got nil") t.Errorf("Expected to be an error, got nil")
} }
w = wrapper w = wrapper
w.MagicEnvelope = "" w.MagicEnvelope = ""
_, err = ParseEncryptedRequest(w, privKey) _, _, err = ParseEncryptedRequest(w, privKey)
if err == nil { if err == nil {
t.Errorf("Expected to be an error, got nil") t.Errorf("Expected to be an error, got nil")
} }
......
...@@ -26,21 +26,22 @@ import ( ...@@ -26,21 +26,22 @@ import (
"strings" "strings"
) )
type signature interface { type SignatureInterface interface {
SignatureText() []string Signature() string
SignatureText(string) []string
} }
type Signature struct { type Signature struct {
entity SignatureInterface
delim string delim string
signatureText []string
Err error Err error
} }
func (signature *Signature) New(sig signature) *Signature { func (signature *Signature) New(entity SignatureInterface) *Signature {
signature.signatureText = sig.SignatureText() signature.entity = entity
signature.delim = SignatureAuthorDelimiter signature.delim = SignatureAuthorDelimiter
if _, ok := sig.(Message); ok { if _, ok := entity.(Message); ok {
signature.delim = SignatureDelimiter signature.delim = SignatureDelimiter
} }
return signature return signature
...@@ -48,7 +49,8 @@ func (signature *Signature) New(sig signature) *Signature { ...@@ -48,7 +49,8 @@ func (signature *Signature) New(sig signature) *Signature {
func (signature *Signature) Sign(privKey *rsa.PrivateKey, sig *string) error { func (signature *Signature) Sign(privKey *rsa.PrivateKey, sig *string) error {
h := sha256.New() h := sha256.New()
h.Write([]byte(strings.Join(signature.signatureText, signature.delim))) h.Write([]byte(strings.Join(
signature.entity.SignatureText(""), signature.delim)))
digest := h.Sum(nil) digest := h.Sum(nil)
rng := rand.Reader rng := rand.Reader
...@@ -61,9 +63,20 @@ func (signature *Signature) Sign(privKey *rsa.PrivateKey, sig *string) error { ...@@ -61,9 +63,20 @@ func (signature *Signature) Sign(privKey *rsa.PrivateKey, sig *string) error {
return nil return nil
} }
func (signature *Signature) Verify(pubKey *rsa.PublicKey, sig []byte) bool { func (signature *Signature) Verify(order string, pubKey *rsa.PublicKey) bool {
message := []byte(strings.Join(signature.signatureText, signature.delim)) sig, err := base64.StdEncoding.DecodeString(signature.entity.Signature())
err := rsa.VerifyPKCS1v15(pubKey, crypto.SHA256, message[:], sig) if err != nil {
sig, err = base64.URLEncoding.DecodeString(signature.entity.Signature())
if err != nil {
signature.Err = err
return false
}
}
orderArr := signature.entity.SignatureText(order)
message := []byte(strings.Join(orderArr, signature.delim))
hashed := sha256.Sum256(message)
err = rsa.VerifyPKCS1v15(pubKey, crypto.SHA256, hashed[:], sig)
signature.Err = err signature.Err = err
return err == nil return err == nil
} }
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