Commit 9fe285ce authored by ale's avatar ale

Use the unified composite type package from ai3/go-common

Avoid implementing our own version of asp/userenckey/u2f serialization
and deserialization.
parent ef542bfe
Pipeline #2557 passed with stages
in 2 minutes and 1 second
......@@ -8,6 +8,7 @@ import (
"strings"
ldaputil "git.autistici.org/ai3/go-common/ldap"
ct "git.autistici.org/ai3/go-common/ldap/compositetypes"
"github.com/tstranex/u2f"
"gopkg.in/ldap.v3"
"gopkg.in/yaml.v2"
......@@ -65,34 +66,23 @@ func getListFromLDAPEntry(entry *ldap.Entry, attr string) []string {
func decodeAppSpecificPasswordList(encodedAsps []string) []*AppSpecificPassword {
var out []*AppSpecificPassword
for _, enc := range encodedAsps {
if p, err := decodeAppSpecificPassword(enc); err == nil {
out = append(out, p)
if p, err := ct.UnmarshalAppSpecificPassword(enc); err == nil {
out = append(out, &AppSpecificPassword{
Service: p.Service,
EncryptedPassword: []byte(p.EncryptedPassword),
})
}
}
return out
}
func decodeAppSpecificPassword(enc string) (*AppSpecificPassword, error) {
parts := strings.SplitN(enc, ":", 2)
if len(parts) != 2 {
return nil, errors.New("bad encoding")
}
return &AppSpecificPassword{
Service: parts[0],
EncryptedPassword: []byte(parts[1]),
}, nil
}
func decodeU2FRegistration(enc string) (reg u2f.Registration, err error) {
err = reg.UnmarshalBinary([]byte(enc))
return
}
func decodeU2FRegistrationList(encRegs []string) []u2f.Registration {
var out []u2f.Registration
for _, enc := range encRegs {
if r, err := decodeU2FRegistration(enc); err == nil {
out = append(out, r)
if r, err := ct.UnmarshalU2FRegistration(enc); err == nil {
if reg, err := r.Decode(); err == nil {
out = append(out, *reg)
}
}
}
return out
......
// Package compositetypes provides Go types for the composite values
// stored in our LDAP database, so that various authentication
// packages can agree on their serialized representation.
//
// These are normally 1-to-many associations that are wrapped into
// repeated LDAP attributes instead of separate nested objects, for
// simplicity and latency reasons.
//
// Whenever there is an 'id' field, it's a unique (per-user)
// identifier used to recognize a specific entry on modify/delete.
//
// The serialized values can be arbitrary []byte sequences (the LDAP
// schema should specify the right types for the associated
// attributes).
//
package compositetypes
import (
"crypto/elliptic"
"errors"
"strings"
"github.com/tstranex/u2f"
)
// AppSpecificPassword stores information on an application-specific
// password.
//
// Serialized as colon-separated fields with the format:
//
// id:service:encrypted_password:comment
//
// Where 'comment' is free-form and can contain colons, no escaping is
// performed.
type AppSpecificPassword struct {
ID string `json:"id"`
Service string `json:"service"`
EncryptedPassword string `json:"encrypted_password"`
Comment string `json:"comment"`
}
// Marshal returns the serialized format.
func (p *AppSpecificPassword) Marshal() string {
return strings.Join([]string{
p.ID,
p.Service,
p.EncryptedPassword,
p.Comment,
}, ":")
}
// UnmarshalAppSpecificPassword parses a serialized representation of
// an AppSpecificPassword.
func UnmarshalAppSpecificPassword(s string) (*AppSpecificPassword, error) {
parts := strings.SplitN(s, ":", 4)
if len(parts) != 4 {
return nil, errors.New("badly encoded app-specific password")
}
return &AppSpecificPassword{
ID: parts[0],
Service: parts[1],
EncryptedPassword: parts[2],
Comment: parts[3],
}, nil
}
// EncryptedKey stores a password-encrypted secret key.
//
// Serialized as colon-separated fields with the format:
//
// id:encrypted_key
//
// The encrypted key is stored as a raw, unencoded byte sequence.
type EncryptedKey struct {
ID string `json:"id"`
EncryptedKey []byte `json:"encrypted_key"`
}
// Marshal returns the serialized format.
func (k *EncryptedKey) Marshal() string {
var b []byte
b = append(b, []byte(k.ID)...)
b = append(b, ':')
b = append(b, k.EncryptedKey...)
return string(b)
}
// UnmarshalEncryptedKey parses the serialized representation of an
// EncryptedKey.
func UnmarshalEncryptedKey(s string) (*EncryptedKey, error) {
idx := strings.IndexByte(s, ':')
if idx < 0 {
return nil, errors.New("badly encoded key")
}
return &EncryptedKey{
ID: s[:idx],
EncryptedKey: []byte(s[idx+1:]),
}, nil
}
// U2FRegistration stores information on a single U2F device
// registration.
//
// The serialized format follows part of the U2F standard and just
// stores 64 bytes of the public key immediately followed by the key
// handle data, with no encoding.
//
// The data in U2FRegistration is still encoded, but it can be turned
// into a usable form (github.com/tstranex/u2f.Registration) later.
type U2FRegistration struct {
KeyHandle []byte `json:"key_handle"`
PublicKey []byte `json:"public_key"`
}
// Marshal returns the serialized format.
func (r *U2FRegistration) Marshal() string {
var b []byte
b = append(b, r.PublicKey...)
b = append(b, r.KeyHandle...)
return string(b)
}
// UnmarshalU2FRegistration parses a U2FRegistration from its serialized format.
func UnmarshalU2FRegistration(s string) (*U2FRegistration, error) {
if len(s) < 64 {
return nil, errors.New("badly encoded u2f registration")
}
b := []byte(s)
return &U2FRegistration{
PublicKey: b[:64],
KeyHandle: b[64:],
}, nil
}
// Decode returns a u2f.Registration object with the decoded public
// key ready for use in verification.
func (r *U2FRegistration) Decode() (*u2f.Registration, error) {
x, y := elliptic.Unmarshal(elliptic.P256(), r.PublicKey)
if x == nil {
return nil, errors.New("invalid public key")
}
var reg u2f.Registration
reg.PubKey.Curve = elliptic.P256()
reg.PubKey.X = x
reg.PubKey.Y = y
reg.KeyHandle = r.KeyHandle
return &reg, nil
}
// NewU2FRegistrationFromData creates a U2FRegistration from a
// u2f.Registration object.
func NewU2FRegistrationFromData(reg *u2f.Registration) *U2FRegistration {
pk := elliptic.Marshal(reg.PubKey.Curve, reg.PubKey.X, reg.PubKey.Y)
return &U2FRegistration{
PublicKey: pk,
KeyHandle: reg.KeyHandle,
}
}
......@@ -20,6 +20,12 @@
"revision": "2934fd63c275d37b0fe60afabb484a251662bd49",
"revisionTime": "2019-02-17T09:01:06Z"
},
{
"checksumSHA1": "X14iCbFCOfaIai/TPi4VJ/OBZjc=",
"path": "git.autistici.org/ai3/go-common/ldap/compositetypes",
"revision": "301958e3493e263eb6ea269bf7b8644fbcd97394",
"revisionTime": "2019-03-21T10:42:03Z"
},
{
"checksumSHA1": "mfFIqmwojDqQdJvjLI3y7YCQ+2c=",
"path": "git.autistici.org/ai3/go-common/pwhash",
......
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