Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Federation Library
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
6
Issues
6
List
Boards
Labels
Service Desk
Milestones
Merge Requests
1
Merge Requests
1
Requirements
Requirements
List
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Operations
Operations
Environments
Packages & Registries
Packages & Registries
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issue
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ganggo
Federation Library
Commits
3b7e47cc
Commit
3b7e47cc
authored
Jan 24, 2018
by
zauberstuhl
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix signature verification by using xml order
fixes
ganggo#1
parent
da96e258
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
115 additions
and
50 deletions
+115
-50
entities.go
entities.go
+14
-15
entities_test.go
entities_test.go
+8
-7
entity_comment.go
entity_comment.go
+9
-2
entity_comment_test.go
entity_comment_test.go
+1
-1
entity_like.go
entity_like.go
+9
-1
helper.go
helper.go
+39
-0
logger.go
logger.go
+1
-5
salmon.go
salmon.go
+5
-3
salmon_test.go
salmon_test.go
+6
-6
signature.go
signature.go
+23
-10
No files found.
entities.go
View file @
3b7e47cc
...
...
@@ -50,11 +50,13 @@ type Entity struct {
Data
interface
{}
`xml:"-"`
}
type
Time
struct
{
time
.
Time
type
Time
string
func
(
m
Message
)
Signature
()
string
{
return
m
.
Sig
.
Sig
}
func
(
m
Message
)
SignatureText
()
[]
string
{
func
(
m
Message
)
SignatureText
(
order
string
)
[]
string
{
return
[]
string
{
m
.
Data
.
Data
,
base64
.
StdEncoding
.
EncodeToString
([]
byte
(
m
.
Data
.
Type
)),
...
...
@@ -63,20 +65,17 @@ func (m Message) SignatureText() []string {
}
}
func
(
t
*
Time
)
MarshalXML
(
e
*
xml
.
Encoder
,
start
xml
.
StartElement
)
error
{
e
.
EncodeElement
(
t
.
Format
(
TIME_FORMAT
),
start
)
return
nil
func
(
t
*
Time
)
New
(
newTime
time
.
Time
)
*
Time
{
*
t
=
Time
(
newTime
.
UTC
()
.
Format
(
TIME_FORMAT
)
)
return
t
}
func
(
t
*
Time
)
UnmarshalXML
(
decoder
*
xml
.
Decoder
,
start
xml
.
StartElement
)
error
{
var
value
string
decoder
.
DecodeElement
(
&
value
,
&
start
)
parse
,
err
:=
time
.
Parse
(
TIME_FORMAT
,
value
)
if
err
!=
nil
{
return
err
}
*
t
=
Time
{
parse
}
return
nil
func
(
t
Time
)
Time
()
(
time
.
Time
,
error
)
{
return
time
.
Parse
(
TIME_FORMAT
,
string
(
t
))
}
func
(
t
Time
)
String
()
string
{
return
string
(
t
)
}
func
(
e
*
Entity
)
UnmarshalXML
(
d
*
xml
.
Decoder
,
start
xml
.
StartElement
)
error
{
...
...
entities_test.go
View file @
3b7e47cc
...
...
@@ -138,9 +138,8 @@ func TestEntitiesTimeMarshalAndUnmarshal(t *testing.T) {
if
err
!=
nil
{
t
.
Errorf
(
"Some error occured while parsing: %v"
,
err
)
}
if
origTime
.
CreatedAt
.
Time
.
Format
(
TIME_FORMAT
)
!=
time
{
t
.
Errorf
(
"Expected to be '%s', got '%s'"
,
origTime
.
CreatedAt
.
Time
.
Format
(
TIME_FORMAT
))
if
origTime
.
CreatedAt
.
String
()
!=
time
{
t
.
Errorf
(
"Expected to be '%s', got '%s'"
,
origTime
.
CreatedAt
.
String
())
}
result
,
err
:=
xml
.
Marshal
(
origTime
)
...
...
@@ -151,8 +150,10 @@ func TestEntitiesTimeMarshalAndUnmarshal(t *testing.T) {
t
.
Errorf
(
"Expected to be '%s', got '%s'"
,
result
,
rawXml
)
}
err
=
xml
.
Unmarshal
([]
byte
(
"<time><CreatedAt></CreatedAt></time>"
),
&
origTime
)
if
err
==
nil
{
t
.
Errorf
(
"Expected an error, got nil"
)
}
// XXX the application server uses time.Now if this happens
// we should change that and let the library decide what is best
//err = xml.Unmarshal([]byte("<time><CreatedAt></CreatedAt></time>"), &origTime)
//if err == nil {
// t.Errorf("Expected an error, got nil")
//}
}
entity_comment.go
View file @
3b7e47cc
...
...
@@ -29,10 +29,17 @@ type EntityComment struct {
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
{
e
.
Author
,
e
.
CreatedAt
.
Format
(
TIME_FORMAT
),
e
.
CreatedAt
.
String
(
),
e
.
Guid
,
e
.
ParentGuid
,
e
.
Text
,
...
...
entity_comment_test.go
View file @
3b7e47cc
...
...
@@ -26,10 +26,10 @@ func TestCommentAppendSignature(t *testing.T) {
comment
:=
EntityComment
{
Author
:
"author@localhost"
,
Guid
:
"1234"
,
CreatedAt
:
Time
{
time
.
Now
()},
ParentGuid
:
"4321"
,
Text
:
"hello world"
,
}
comment
.
CreatedAt
.
New
(
time
.
Now
())
if
comment
.
AuthorSignature
!=
""
{
t
.
Errorf
(
"Expected to be empty, got %s"
,
comment
.
AuthorSignature
)
...
...
entity_like.go
View file @
3b7e47cc
...
...
@@ -32,7 +32,15 @@ type EntityLike struct {
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"
if
e
.
Positive
{
positive
=
"true"
...
...
helper.go
View file @
3b7e47cc
...
...
@@ -23,8 +23,47 @@ import (
"crypto/x509"
"encoding/pem"
"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
)
{
block
,
_
:=
pem
.
Decode
(
decodedKey
)
if
block
==
nil
{
...
...
logger.go
View file @
3b7e47cc
...
...
@@ -64,11 +64,7 @@ func SetLogger(writer LogWriter) {
}
func
(
l
Logger
)
Info
(
values
...
interface
{})
{
values
=
append
(
values
,
[]
interface
{}{
""
})
copy
(
values
[
1
:
],
values
[
0
:
])
values
[
0
]
=
l
.
Prefix
values
=
append
(
values
,
LOG_C_RESET
)
l
.
Println
(
values
)
l
.
Println
(
l
.
Prefix
,
values
,
LOG_C_RESET
)
}
func
(
l
Logger
)
Error
(
values
...
interface
{})
{
...
...
salmon.go
View file @
3b7e47cc
...
...
@@ -24,8 +24,7 @@ import (
"strings"
)
func
ParseDecryptedRequest
(
entityXML
[]
byte
)
(
entity
Entity
,
err
error
)
{
var
message
Message
func
ParseDecryptedRequest
(
entityXML
[]
byte
)
(
message
Message
,
entity
Entity
,
err
error
)
{
err
=
xml
.
Unmarshal
(
entityXML
,
&
message
)
if
err
!=
nil
{
logger
.
Error
(
err
)
...
...
@@ -48,18 +47,21 @@ func ParseDecryptedRequest(entityXML []byte) (entity Entity, err error) {
return
}
message
.
Sig
.
KeyId
=
string
(
keyId
)
logger
.
Info
(
"Entity sender"
,
message
.
Sig
.
KeyId
)
data
,
err
:=
base64
.
URLEncoding
.
DecodeString
(
message
.
Data
.
Data
)
if
err
!=
nil
{
logger
.
Error
(
err
)
return
}
logger
.
Info
(
"Entity raw"
,
string
(
data
))
entity
.
SignatureOrder
,
err
=
FetchEntityOrder
(
data
)
if
err
!=
nil
{
logger
.
Error
(
err
)
return
}
logger
.
Info
(
"Entity order"
,
entity
.
SignatureOrder
)
err
=
xml
.
Unmarshal
(
data
,
&
entity
)
if
err
!=
nil
{
...
...
@@ -69,7 +71,7 @@ func ParseDecryptedRequest(entityXML []byte) (entity Entity, err error) {
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
)
if
err
!=
nil
{
logger
.
Error
(
err
)
...
...
salmon_test.go
View file @
3b7e47cc
...
...
@@ -22,17 +22,17 @@ import "testing"
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>`
)
entity
,
err
:=
ParseDecryptedRequest
([]
byte
(
""
))
_
,
entity
,
err
:=
ParseDecryptedRequest
([]
byte
(
""
))
if
err
==
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
{
t
.
Errorf
(
"Expected to be an error, got nil"
)
}
entity
,
err
=
ParseDecryptedRequest
(
xml
)
_
,
entity
,
err
=
ParseDecryptedRequest
(
xml
)
if
err
!=
nil
{
t
.
Errorf
(
"Some error occured while parsing: %v"
,
err
)
}
...
...
@@ -51,7 +51,7 @@ func TestParseEncryptedRequest(t *testing.T) {
t
.
Errorf
(
"Some error occured while parsing: %v"
,
err
)
}
entity
,
err
:=
ParseEncryptedRequest
(
wrapper
,
privKey
)
_
,
entity
,
err
:=
ParseEncryptedRequest
(
wrapper
,
privKey
)
if
err
!=
nil
{
t
.
Errorf
(
"Some error occured while parsing: %v"
,
err
)
}
...
...
@@ -60,14 +60,14 @@ func TestParseEncryptedRequest(t *testing.T) {
w
:=
wrapper
w
.
AesKey
=
""
_
,
err
=
ParseEncryptedRequest
(
w
,
privKey
)
_
,
_
,
err
=
ParseEncryptedRequest
(
w
,
privKey
)
if
err
==
nil
{
t
.
Errorf
(
"Expected to be an error, got nil"
)
}
w
=
wrapper
w
.
MagicEnvelope
=
""
_
,
err
=
ParseEncryptedRequest
(
w
,
privKey
)
_
,
_
,
err
=
ParseEncryptedRequest
(
w
,
privKey
)
if
err
==
nil
{
t
.
Errorf
(
"Expected to be an error, got nil"
)
}
...
...
signature.go
View file @
3b7e47cc
...
...
@@ -26,21 +26,22 @@ import (
"strings"
)
type
signature
interface
{
SignatureText
()
[]
string
type
SignatureInterface
interface
{
Signature
()
string
SignatureText
(
string
)
[]
string
}
type
Signature
struct
{
entity
SignatureInterface
delim
string
signatureText
[]
string
Err
error
}
func
(
signature
*
Signature
)
New
(
sig
signatur
e
)
*
Signature
{
signature
.
signatureText
=
sig
.
SignatureText
()
func
(
signature
*
Signature
)
New
(
entity
SignatureInterfac
e
)
*
Signature
{
signature
.
entity
=
entity
signature
.
delim
=
SignatureAuthorDelimiter
if
_
,
ok
:=
sig
.
(
Message
);
ok
{
if
_
,
ok
:=
entity
.
(
Message
);
ok
{
signature
.
delim
=
SignatureDelimiter
}
return
signature
...
...
@@ -48,7 +49,8 @@ func (signature *Signature) New(sig signature) *Signature {
func
(
signature
*
Signature
)
Sign
(
privKey
*
rsa
.
PrivateKey
,
sig
*
string
)
error
{
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
)
rng
:=
rand
.
Reader
...
...
@@ -61,9 +63,20 @@ func (signature *Signature) Sign(privKey *rsa.PrivateKey, sig *string) error {
return
nil
}
func
(
signature
*
Signature
)
Verify
(
pubKey
*
rsa
.
PublicKey
,
sig
[]
byte
)
bool
{
message
:=
[]
byte
(
strings
.
Join
(
signature
.
signatureText
,
signature
.
delim
))
err
:=
rsa
.
VerifyPKCS1v15
(
pubKey
,
crypto
.
SHA256
,
message
[
:
],
sig
)
func
(
signature
*
Signature
)
Verify
(
order
string
,
pubKey
*
rsa
.
PublicKey
)
bool
{
sig
,
err
:=
base64
.
StdEncoding
.
DecodeString
(
signature
.
entity
.
Signature
())
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
return
err
==
nil
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment