From 428bb86de2c64e8f8ce8127eac95faa2529ce0df Mon Sep 17 00:00:00 2001
From: Martin Dosch
Date: Mon, 18 Apr 2022 11:16:41 +0200
Subject: [PATCH] Ox: Add private key import.
---
README.md | 4 ++-
main.go | 19 ++++++++++--
man/go-sendxmpp.1 | 6 +++-
man/go-sendxmpp.1.html | 9 ++++--
man/go-sendxmpp.1.ronn | 9 ++++--
ox.go | 66 +++++++++++++++++++++++++++++++++++-------
6 files changed, 95 insertions(+), 18 deletions(-)
diff --git a/README.md b/README.md
index 19d77df..b43a66d 100644
--- a/README.md
+++ b/README.md
@@ -83,7 +83,7 @@ If no configuration file is present or if the values should be overridden it is
the account details via command line options:
```plain
-Usage: go-sendxmpp [-cdilnt] [-f value] [--help] [--http-upload value] [-j value] [-m value] [--muc-password value] [--ox] [--ox-genprivkey] [--ox-passphrase value] [-p value] [--raw] [-r value] [--timeout value] [--tls-version value] [-u value] [--version] [parameters ...]
+Usage: go-sendxmpp [-cdilnt] [-f value] [--help] [--http-upload value] [-j value] [-m value] [--muc-password value] [--ox] [--ox-genprivkey] [--ox-import-privkey value] [--ox-passphrase value] [-p value] [--raw] [-r value] [--timeout value] [--tls-version value] [-u value] [--version] [parameters ...]
-c, --chatroom Send message to a chatroom.
-d, --debug Show debugging info.
-f, --file=value Set configuration file. (Default:
@@ -105,6 +105,8 @@ Usage: go-sendxmpp [-cdilnt] [-f value] [--help] [--http-upload value] [-j value
--ox-genprivkey
Generate a public OpenPGP key for the given JID and publish
the corresponding public key.
+ --ox-import-privkey=value
+ Import an existing private OpenPGP key.
--ox-passphrase=value
Passphrase for locking and unlocking the private OpenPGP
key.
diff --git a/main.go b/main.go
index d3d8a21..34964f3 100644
--- a/main.go
+++ b/main.go
@@ -111,6 +111,8 @@ func main() {
"Generate a public OpenPGP key for the given JID and publish the corresponding public key.")
flagOxPassphrase := getopt.StringLong("ox-passphrase", 0, "",
"Passphrase for locking and unlocking the private OpenPGP key.")
+ flagOxImportPrivKey := getopt.StringLong("ox-import-privkey", 0, "",
+ "Import an existing private OpenPGP key.")
// Parse command line flags.
getopt.Parse()
@@ -145,8 +147,8 @@ func main() {
// For listening or sending raw XML it's not required to specify a recipient except
// when sending raw messages to MUCs (go-sendxmpp will join the MUC automatically).
recipientsList := getopt.Args()
- if (len(recipientsList) == 0 && !*flagRaw && !*flagListen && !*flagOxGenPrivKey) ||
- (len(recipientsList) == 0 && *flagChatroom) {
+ if (len(recipientsList) == 0 && !*flagRaw && !*flagListen && !*flagOxGenPrivKey &&
+ *flagOxImportPrivKey == "") || (len(recipientsList) == 0 && *flagChatroom) {
log.Fatal("No recipient specified.")
}
@@ -287,6 +289,19 @@ func main() {
os.Exit(0)
}
+ if *flagOxImportPrivKey != "" {
+ validatedOwnJid, err := MarshalJID(user)
+ if err != nil {
+ log.Fatal(err)
+ }
+ err = oxImportPrivKey(validatedOwnJid, *flagOxImportPrivKey,
+ client)
+ if err != nil {
+ log.Fatal(err)
+ }
+ os.Exit(0)
+ }
+
if *flagOx {
validatedOwnJid, err := MarshalJID(user)
if err != nil {
diff --git a/man/go-sendxmpp.1 b/man/go-sendxmpp.1
index 2a5f937..4d0b265 100644
--- a/man/go-sendxmpp.1
+++ b/man/go-sendxmpp.1
@@ -38,7 +38,11 @@ You can either pipe a programs output to \fBgo\-sendxmpp\fR, write in your termi
.br
There is also no check whether the recipients key is trusted as there is no local keyring used\. Go\-sendxmpp just uses the most recent key that is provided via pubsub and checks that it is not expired\.
.P
-\fB\-\-ox\-genprivkey\fR: Generate a public OpenPGP key for the given JID and publish the corresponding public key\. Go\-sendxmpp will save the key in \fB$XDG_DATA_HOME/go\-sendxmpp/oxprivkeys\fR or \fB$HOME/\.local/share/go\-sendxmpp/oxprivkeys\fR\. To protect the key you might want to set a passphrase using \fB\-\-ox\-passphrase\fR while generating the key\.
+\fB\-\-ox\-genprivkey\fR: Generate a public OpenPGP key for the given JID and publish the corresponding public key\. Go\-sendxmpp will save the key in \fB$XDG_DATA_HOME/go\-sendxmpp/oxprivkeys\fR or \fB$HOME/\.local/share/go\-sendxmpp/oxprivkeys\fR\. To protect the key a passphrase might be set using \fB\-\-ox\-passphrase\fR while generating the key\.
+.br
+If there is an existing private key for "OpenPGP for XMPP" created by another client (e\.g\. profanity) it might be imported using \fB\-\-ox\-import\-privkey\fR\.
+.P
+\fB\-\-ox\-import\-privkey\fR=[\fIvalue\fR]: Import an existing private OpenPGP key\.
.P
\fB\-\-ox\-passphrase\fR=[\fIvalue\fR]: Passphrase for locking and unlocking the private OpenPGP key\.
.P
diff --git a/man/go-sendxmpp.1.html b/man/go-sendxmpp.1.html
index 04a391a..5fb35ca 100644
--- a/man/go-sendxmpp.1.html
+++ b/man/go-sendxmpp.1.html
@@ -137,8 +137,13 @@ file location is specified with -f
or --file
.
--ox-genprivkey
:
Generate a public OpenPGP key for the given JID and publish the corresponding public key.
Go-sendxmpp will save the key in $XDG_DATA_HOME/go-sendxmpp/oxprivkeys
or
- $HOME/.local/share/go-sendxmpp/oxprivkeys
. To protect the key you might want to set a
- passphrase using --ox-passphrase
while generating the key.
+ $HOME/.local/share/go-sendxmpp/oxprivkeys
. To protect the key a passphrase might be set
+ using --ox-passphrase
while generating the key.
+ If there is an existing private key for "OpenPGP for XMPP" created by another client (e.g. profanity)
+ it might be imported using --ox-import-privkey
.
+
+--ox-import-privkey
=[value]:
+ Import an existing private OpenPGP key.
--ox-passphrase
=[value]:
Passphrase for locking and unlocking the private OpenPGP key.
diff --git a/man/go-sendxmpp.1.ronn b/man/go-sendxmpp.1.ronn
index 3d6b14d..6b40073 100644
--- a/man/go-sendxmpp.1.ronn
+++ b/man/go-sendxmpp.1.ronn
@@ -62,8 +62,13 @@ file location is specified with `-f` or `--file`.
`--ox-genprivkey`:
Generate a public OpenPGP key for the given JID and publish the corresponding public key.
Go-sendxmpp will save the key in `$XDG_DATA_HOME/go-sendxmpp/oxprivkeys` or
- `$HOME/.local/share/go-sendxmpp/oxprivkeys`. To protect the key you might want to set a
- passphrase using `--ox-passphrase` while generating the key.
+ `$HOME/.local/share/go-sendxmpp/oxprivkeys`. To protect the key a passphrase might be set
+ using `--ox-passphrase` while generating the key.
+ If there is an existing private key for "OpenPGP for XMPP" created by another client (e.g. profanity)
+ it might be imported using `--ox-import-privkey`.
+
+ `--ox-import-privkey`=[]:
+ Import an existing private OpenPGP key.
`--ox-passphrase`=[]:
Passphrase for locking and unlocking the private OpenPGP key.
diff --git a/ox.go b/ox.go
index e3fbaad..52146fd 100644
--- a/ox.go
+++ b/ox.go
@@ -19,6 +19,52 @@ import (
"github.com/mattn/go-xmpp" // BSD-3-Clause
)
+func oxImportPrivKey(jid string, privKeyLocation string, client *xmpp.Client) error {
+ xmppUri := "xmpp:" + jid
+ buffer, err := readFile(privKeyLocation)
+ if err != nil {
+ return err
+ }
+ key, err := crypto.NewKey(buffer.Bytes())
+ if err != nil {
+ key, err = crypto.NewKeyFromArmored(buffer.String())
+ if err != nil {
+ return err
+ }
+ }
+ entity := key.GetEntity()
+ if entity.Identities[xmppUri] == nil {
+ return errors.New("Key identity is not " + xmppUri)
+ }
+ pk, err := key.GetPublicKey()
+ if err != nil {
+ return err
+ }
+ pubKey, err := crypto.NewKey(pk)
+ if err != nil {
+ return err
+ }
+ fingerprint := strings.ToUpper(pubKey.GetFingerprint())
+ _, err = oxRecvPublicKey(client, jid, fingerprint)
+ if err != nil {
+ return errors.New("Key not found in pubsub: " + fingerprint)
+ }
+ location, err := oxGetPrivKeyLoc(jid)
+ if err != nil {
+ return err
+ }
+ keySerialized, err := key.Serialize()
+ if err != nil {
+ return err
+ }
+ err = oxStorePrivKey(location,
+ base64.StdEncoding.EncodeToString(keySerialized))
+ if err != nil {
+ log.Fatal(err)
+ }
+ return nil
+}
+
func oxGetPrivKeyLoc(jid string) (string, error) {
var err error
var homeDir, dataDir string
@@ -89,19 +135,15 @@ func oxGetPrivKey(jid string, passphrase string) (*crypto.Key, error) {
return key, nil
}
-func oxStorePrivKey(jid string, privKey string) error {
- dataFile, err := oxGetPrivKeyLoc(jid)
- if err != nil {
- log.Fatal(err)
- }
+func oxStorePrivKey(location string, privKey string) error {
var file *os.File
- if _, err := os.Stat(dataFile); os.IsNotExist(err) {
- file, err = os.Create(dataFile)
+ if _, err := os.Stat(location); os.IsNotExist(err) {
+ file, err = os.Create(location)
if err != nil {
return err
}
} else {
- file, err = os.OpenFile(dataFile, os.O_RDWR, 0600)
+ file, err = os.OpenFile(location, os.O_RDWR, 0600)
if err != nil {
return err
}
@@ -112,7 +154,7 @@ func oxStorePrivKey(jid string, privKey string) error {
} else {
_ = file.Chmod(os.FileMode(0200))
}
- _, err = file.Write([]byte(privKey))
+ _, err := file.Write([]byte(privKey))
if err != nil {
return err
}
@@ -141,7 +183,11 @@ func oxGenPrivKey(jid string, client *xmpp.Client, passphrase string) error {
if err != nil {
return err
}
- err = oxStorePrivKey(jid,
+ location, err := oxGetPrivKeyLoc(jid)
+ if err != nil {
+ return err
+ }
+ err = oxStorePrivKey(location,
base64.StdEncoding.EncodeToString(keySerialized))
if err != nil {
log.Fatal(err)