// Domain returns the domain of the uid identity. func (msg *Message) Domain() string { _, domain, err := identity.Split(msg.UIDContent.IDENTITY) if err != nil { // UID messages have to be valid panic(log.Critical(err)) } return domain }
// Localpart returns the localpart of the uid identity. func (msg *Message) Localpart() string { lp, _, err := identity.Split(msg.UIDContent.IDENTITY) if err != nil { // UID messages have to be valid panic(log.Critical(err)) } return lp }
// Check that the content of the UID message is consistent with it's version. func (msg *Message) Check() error { // we only support version 1.0 at this stage if msg.UIDContent.VERSION != "1.0" { return log.Errorf("uid: unknown UIDContent.VERSION: %s", msg.UIDContent.VERSION) } // generic checks optional := Optional.String() if msg.UIDContent.PREFERENCES.FORWARDSEC != optional { if msg.UIDContent.MIXADDRESS != "" { return log.Errorf("uid: MIXADDRESS must be null, if FORWARDSEC is not %q", optional) } if msg.UIDContent.NYMADDRESS != "" { return log.Errorf("uid: NYMADDRESS must be null, if FORWARDSEC is not %q", optional) } } if err := identity.IsMapped(msg.UIDContent.IDENTITY); err != nil { return log.Error(err) } // check SIGKEY if msg.UIDContent.SIGKEY.CIPHERSUITE != DefaultCiphersuite { return log.Error("uid: UIDContent.SIGKEY.CIPHERSUITE != DefaultCiphersuite") } if msg.UIDContent.SIGKEY.FUNCTION != "ED25519" { return log.Error("uid: UIDContent.SIGKEY.FUNCTION != \"ED25519\"") } // make sure LASTENTRY is parseable for a non-keyserver localpart. // For keyservers the LASTENTRY can be empty, iff this is the first entry // in the hashchain. lp, _, _ := identity.Split(msg.UIDContent.IDENTITY) if lp != "keyserver" { _, _, _, _, _, _, err := hashchain.SplitEntry(msg.UIDContent.LASTENTRY) if err != nil { return err } } // make sure ESCROWSIGNATURE and USERSIGNATURE are not set at the same time if msg.ESCROWSIGNATURE != "" && msg.USERSIGNATURE != "" { return log.Error("uid: USERSIGNATURE and ESCROWSIGNATURE cannot be set at the same time") } // version 1.0 specific checks return msg.checkV1_0() }
// GetPrivateIdentitiesForDomain returns all private identities for the given // domain from keyDB. func (keyDB *KeyDB) GetPrivateIdentitiesForDomain(domain string) ([]string, error) { var identities []string all, err := keyDB.GetPrivateIdentities() if err != nil { return nil, err } dmn := identity.MapDomain(domain) for _, id := range all { _, idDomain, err := identity.Split(id) if err != nil { return nil, err } if idDomain == dmn { identities = append(identities, id) } } return identities, nil }
func (msg *Message) checkV1_0() error { // UIDContent.PREFERENCES.FORWARDSEC must be "strict" strict := Strict.String() if msg.UIDContent.PREFERENCES.FORWARDSEC != strict { return log.Errorf("uid: FORWARDSEC must be %q", strict) } // UIDContent.PUBKEYS contains exactly one ECDHE25519 key for the default // ciphersuite if len(msg.UIDContent.PUBKEYS) != 1 { return log.Error("uid: UIDContent.PUBKEYS must contain exactly one key") } if msg.UIDContent.PUBKEYS[0].CIPHERSUITE != DefaultCiphersuite { return log.Error("uid: UIDContent.PUBKEYS[0].CIPHERSUITE != DefaultCiphersuite") } if msg.UIDContent.PUBKEYS[0].FUNCTION != "ECDHE25519" { return log.Error("uid: UIDContent.PUBKEYS[0].FUNCTION != \"ECDHE25519\"") } // UIDContent.SIGESCROW must be zero-value. if msg.UIDContent.SIGESCROW != nil { if msg.UIDContent.SIGESCROW.CIPHERSUITE != "" || msg.UIDContent.SIGESCROW.FUNCTION != "" || msg.UIDContent.SIGESCROW.HASH != "" || msg.UIDContent.SIGESCROW.PUBKEY != "" { return log.Error("uid: UIDContent.SIGESCROW must be zero-value") } } // UIDContent.REPOURIS contains one entry which is the domain of // UIDContent.IDENTITY _, domain, _ := identity.Split(msg.UIDContent.IDENTITY) if len(msg.UIDContent.REPOURIS) != 1 || msg.UIDContent.REPOURIS[0] != domain { return log.Error("uid: UIDContent.REPOURIS must contain one entry (domain of identity)") } // UIDContent.CHAINLINK must be zero-value if msg.UIDContent.CHAINLINK != nil { if !reflect.DeepEqual(msg.UIDContent.CHAINLINK, chainlink{}) { return log.Error("uid: UIDContent.CHAINLINK must be zero-value") } } return nil }
// Create creates a new UID message for the given userID and self-signs it. // It automatically creates all necessary keys. If sigescrow is true, an // escrow key is included in the created UID message. // Necessary randomness is read from rand. func Create( userID string, sigescrow bool, mixaddress, nymaddress string, pfsPreference PFSPreference, lastEntry string, rand io.Reader, ) (*Message, error) { var msg Message var err error // check user ID (identity) if err := identity.IsMapped(userID); err != nil { return nil, log.Error(err) } msg.UIDContent.VERSION = ProtocolVersion msg.UIDContent.MSGCOUNT = 0 // this is the first UIDMessage msg.UIDContent.NOTAFTER = uint64(times.OneYearLater()) // TODO: make this settable! msg.UIDContent.NOTBEFORE = 0 // TODO: make this settable if pfsPreference == Optional { msg.UIDContent.MIXADDRESS = mixaddress msg.UIDContent.NYMADDRESS = nymaddress } else { msg.UIDContent.MIXADDRESS = "" msg.UIDContent.NYMADDRESS = "" } msg.UIDContent.IDENTITY = userID if err = msg.UIDContent.SIGKEY.initSigKey(rand); err != nil { return nil, err } msg.UIDContent.PUBKEYS = make([]KeyEntry, 1) if err := msg.UIDContent.PUBKEYS[0].InitDHKey(rand); err != nil { return nil, err } if sigescrow { msg.UIDContent.SIGESCROW = new(KeyEntry) if err = msg.UIDContent.SIGESCROW.initSigKey(rand); err != nil { return nil, err } } // make sure LASTENTRY is parseable for a non-keyserver localpart. // For keyservers the LASTENTRY can be empty, iff this is the first entry // in the hashchain. lp, domain, _ := identity.Split(msg.UIDContent.IDENTITY) if lp != "keyserver" { if _, _, _, _, _, _, err := hashchain.SplitEntry(lastEntry); err != nil { return nil, err } } msg.UIDContent.LASTENTRY = lastEntry // set REPOURIS to the domain of UIDContent.IDENTITY // TODO: support different KeyInit repository configurations msg.UIDContent.REPOURIS = []string{domain} msg.UIDContent.PREFERENCES.FORWARDSEC = pfsPreference.String() msg.UIDContent.PREFERENCES.CIPHERSUITES = []string{DefaultCiphersuite} // TODO: CHAINLINK (later protocol version) // theses signatures are always empty for messages the first UIDMessage msg.ESCROWSIGNATURE = "" msg.USERSIGNATURE = "" selfsig := msg.UIDContent.SIGKEY.ed25519Key.Sign(msg.UIDContent.JSON()) msg.SELFSIGNATURE = base64.Encode(selfsig) // TODO: LINKAUTHORITY return &msg, nil }
func (ce *CtrlEngine) msgSend( c *cli.Context, id string, all bool, failDelivery bool, ) error { nyms, err := ce.getNyms(id, all) if err != nil { return err } for _, nym := range nyms { // clear resend status for old messages in outqueue if err := ce.msgDB.ClearResendOutQueue(nym); err != nil { return err } // process old messages in outqueue if err := ce.procOutQueue(c, nym, failDelivery); err != nil { return err } /* ids, err := ce.msgDB.GetMsgIDs(nym) if err != nil { return err } for _, id := range ids { log.Debugf("id=%d, to=%s", id.MsgID, id.To) } */ // add all undelivered messages to outqueue var recvNymAddress string for { msgID, peer, msg, sign, minDelay, maxDelay, err := ce.msgDB.GetUndeliveredMessage(nym) if err != nil { return err } if peer == "" { log.Debug("break") break // no more undelivered messages } // determine recipient nymaddress for encryption, if necessary if recvNymAddress == "" { // TODO! (implement more accounts? delay settings?) privkey, server, secret, minDelay, maxDelay, _, err := ce.msgDB.GetAccount(nym, "") if err != nil { return err } _, domain, err := identity.Split(nym) if err != nil { return err } expire := times.ThirtyDaysLater() // TODO: make this settable singleUse := false // TODO correct? var pubkey [ed25519.PublicKeySize]byte copy(pubkey[:], privkey[32:]) _, recvNymAddress, err = util.NewNymAddress(domain, secret[:], expire, singleUse, minDelay, maxDelay, nym, &pubkey, server, def.CACert) if err != nil { return err } } // encrypt enc, nymaddress, err := mutecryptEncrypt(c, nym, peer, ce.passphrase, msg, sign, recvNymAddress) if err != nil { return log.Error(err) } // add to outqueue log.Debug("add") err = ce.msgDB.AddOutQueue(nym, msgID, enc, nymaddress, minDelay, maxDelay) if err != nil { return log.Error(err) } } // process new messages in outqueue if err := ce.procOutQueue(c, nym, failDelivery); err != nil { return err } } return nil }