Merge branch 'master' of ssh+git://playfair.gnupg.org/git/gpgme
* Also fixed a small grammatical error highlighted by a merge conflict (in the python bindings howto).
This commit is contained in:
commit
fed024eff1
@ -6,6 +6,7 @@
|
|||||||
#+LATEX_HEADER: \usepackage[margin=1in]{geometry}
|
#+LATEX_HEADER: \usepackage[margin=1in]{geometry}
|
||||||
#+LATEX_HEADER: \setmainfont[Ligatures={Common}]{Times New Roman}
|
#+LATEX_HEADER: \setmainfont[Ligatures={Common}]{Times New Roman}
|
||||||
#+LATEX_HEADER: \author{Ben McGinnes <ben@gnupg.org>}
|
#+LATEX_HEADER: \author{Ben McGinnes <ben@gnupg.org>}
|
||||||
|
#+HTML_HEAD_EXTRA: <link type="application/rss+xml" href="https://git.gnupg.org/cgi-bin/gitweb.cgi?p=gpgme.git;a=rss;f=lang/python/docs/GPGMEpythonHOWTOen.org"/>
|
||||||
|
|
||||||
|
|
||||||
* Introduction
|
* Introduction
|
||||||
@ -164,7 +165,7 @@
|
|||||||
This package is the origin of these bindings, though they are
|
This package is the origin of these bindings, though they are
|
||||||
somewhat different now. For details of when and how the PyME
|
somewhat different now. For details of when and how the PyME
|
||||||
package was folded back into GPGME itself see the /Short History/
|
package was folded back into GPGME itself see the /Short History/
|
||||||
document[fn:1] in this Python bindings =docs= directory.[fn:2]
|
document[fn:1] in the Python bindings =docs= directory.[fn:2]
|
||||||
|
|
||||||
The PyME package was first released in 2002 and was also the first
|
The PyME package was first released in 2002 and was also the first
|
||||||
attempt to implement a low level binding to GPGME. In doing so it
|
attempt to implement a low level binding to GPGME. In doing so it
|
||||||
@ -536,8 +537,7 @@
|
|||||||
c = gpg.Context(armor=True)
|
c = gpg.Context(armor=True)
|
||||||
rkey = list(c.keylist(pattern=a_key, secret=False))
|
rkey = list(c.keylist(pattern=a_key, secret=False))
|
||||||
ciphertext, result, sign_result = c.encrypt(text, recipients=rkey,
|
ciphertext, result, sign_result = c.encrypt(text, recipients=rkey,
|
||||||
sign=True, always_trust=True,
|
sign=True, always_trust=True, add_encrypt_to=True)
|
||||||
add_encrypt_to=True)
|
|
||||||
|
|
||||||
with open("secret_plans.txt.asc", "wb") as afile:
|
with open("secret_plans.txt.asc", "wb") as afile:
|
||||||
afile.write(ciphertext)
|
afile.write(ciphertext)
|
||||||
@ -588,10 +588,10 @@
|
|||||||
logrus.append(rpattern[i])
|
logrus.append(rpattern[i])
|
||||||
|
|
||||||
ciphertext, result, sign_result = c.encrypt(text, recipients=logrus, sign=False,
|
ciphertext, result, sign_result = c.encrypt(text, recipients=logrus, sign=False,
|
||||||
always_trust=True)
|
always_trust=True)
|
||||||
|
|
||||||
with open("secret_plans.txt.asc", "wb") as afile:
|
with open("secret_plans.txt.asc", "wb") as afile:
|
||||||
afile.write(ciphertext)
|
afile.write(ciphertext)
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
All it would take to change the above example to sign the message
|
All it would take to change the above example to sign the message
|
||||||
@ -600,7 +600,7 @@
|
|||||||
|
|
||||||
#+begin_src python
|
#+begin_src python
|
||||||
ciphertext, result, sign_result = c.encrypt(text, recipients=logrus,
|
ciphertext, result, sign_result = c.encrypt(text, recipients=logrus,
|
||||||
always_trust=True,
|
always_trust=True,
|
||||||
add_encrypt_to=True)
|
add_encrypt_to=True)
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
@ -618,7 +618,7 @@
|
|||||||
import gpg
|
import gpg
|
||||||
|
|
||||||
with open("secret_plans.txt.asc", "rb") as afile:
|
with open("secret_plans.txt.asc", "rb") as afile:
|
||||||
text = afile.read()
|
text = afile.read()
|
||||||
|
|
||||||
c = gpg.Context(armor=True)
|
c = gpg.Context(armor=True)
|
||||||
rpattern = list(c.keylist(pattern="@gnupg.org", secret=False))
|
rpattern = list(c.keylist(pattern="@gnupg.org", secret=False))
|
||||||
@ -629,21 +629,23 @@
|
|||||||
logrus.append(rpattern[i])
|
logrus.append(rpattern[i])
|
||||||
|
|
||||||
try:
|
try:
|
||||||
ciphertext, result, sign_result = c.encrypt(text, recipients=logrus, add_encrypt_to=True)
|
ciphertext, result, sign_result = c.encrypt(text, recipients=logrus,
|
||||||
|
add_encrypt_to=True)
|
||||||
except gpg.errors.InvalidRecipients as e:
|
except gpg.errors.InvalidRecipients as e:
|
||||||
for i in range(len(e.recipients)):
|
for i in range(len(e.recipients)):
|
||||||
for n in range(len(logrus)):
|
for n in range(len(logrus)):
|
||||||
if logrus[n].fpr == e.recipients[i].fpr:
|
if logrus[n].fpr == e.recipients[i].fpr:
|
||||||
logrus.remove(logrus[n])
|
logrus.remove(logrus[n])
|
||||||
else:
|
else:
|
||||||
pass
|
pass
|
||||||
try:
|
try:
|
||||||
ciphertext, result, sign_result = c.encrypt(text, recipients=logrus, add_encrypt_to=True)
|
ciphertext, result, sign_result = c.encrypt(text, recipients=logrus,
|
||||||
|
add_encrypt_to=True)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
with open("secret_plans.txt.asc", "wb") as afile:
|
with open("secret_plans.txt.asc", "wb") as afile:
|
||||||
afile.write(ciphertext)
|
afile.write(ciphertext)
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
This will attempt to encrypt to all the keys searched for, then
|
This will attempt to encrypt to all the keys searched for, then
|
||||||
@ -669,16 +671,18 @@
|
|||||||
|
|
||||||
ciphertext = input("Enter path and filename of encrypted file: ")
|
ciphertext = input("Enter path and filename of encrypted file: ")
|
||||||
newfile = input("Enter path and filename of file to save decrypted data to: ")
|
newfile = input("Enter path and filename of file to save decrypted data to: ")
|
||||||
|
|
||||||
with open(ciphertext, "rb") as cfile:
|
with open(ciphertext, "rb") as cfile:
|
||||||
plaintext, result, verify_result = gpg.Context().decrypt(cfile)
|
plaintext, result, verify_result = gpg.Context().decrypt(cfile)
|
||||||
|
|
||||||
with open(newfile, "wb") as nfile:
|
with open(newfile, "wb") as nfile:
|
||||||
nfile.write(plaintext)
|
nfile.write(plaintext)
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
The data available in plaintext in this example is the decrypted
|
The data available in =plaintext= in this example is the decrypted
|
||||||
content as a byte object in =plaintext[0]=, the recipient key IDs
|
content as a byte object, the recipient key IDs and algorithms in
|
||||||
and algorithms in =plaintext[1]= and the results of verifying any
|
=result= and the results of verifying any signatures of the data in
|
||||||
signatures of the data in =plaintext[0]=.
|
=verify_result=.
|
||||||
|
|
||||||
|
|
||||||
** Signing text and files
|
** Signing text and files
|
||||||
@ -1078,8 +1082,8 @@
|
|||||||
c.home_dir = "~/.gnupg-dm"
|
c.home_dir = "~/.gnupg-dm"
|
||||||
userid = "Danger Mouse <dm@secret.example.net>"
|
userid = "Danger Mouse <dm@secret.example.net>"
|
||||||
|
|
||||||
dmkey = c.create_key(userid, algorithm = "rsa3072", expires_in = 31536000,
|
dmkey = c.create_key(userid, algorithm="rsa3072", expires_in=31536000,
|
||||||
sign = True, certify = True)
|
sign=True, certify=True)
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
One thing to note here is the use of setting the =c.home_dir=
|
One thing to note here is the use of setting the =c.home_dir=
|
||||||
@ -1091,6 +1095,10 @@
|
|||||||
permissions set to only permit access by the directory owner. On
|
permissions set to only permit access by the directory owner. On
|
||||||
posix systems this means setting the directory permissions to 700.
|
posix systems this means setting the directory permissions to 700.
|
||||||
|
|
||||||
|
The =temp-homedir-config.py= script in the HOWTO examples directory
|
||||||
|
will create an alternative homedir with these configuration options
|
||||||
|
already set and the correct directory and file permissions.
|
||||||
|
|
||||||
The successful generation of the key can be confirmed via the
|
The successful generation of the key can be confirmed via the
|
||||||
returned =GenkeyResult= object, which includes the following data:
|
returned =GenkeyResult= object, which includes the following data:
|
||||||
|
|
||||||
@ -1167,9 +1175,9 @@
|
|||||||
c = gpg.Context()
|
c = gpg.Context()
|
||||||
c.home_dir = "~/.gnupg-dm"
|
c.home_dir = "~/.gnupg-dm"
|
||||||
|
|
||||||
key = c.get_key(dmkey.fpr, secret = True)
|
key = c.get_key(dmkey.fpr, secret=True)
|
||||||
dmsub = c.create_subkey(key, algorithm = "rsa3072", expires_in = 15768000,
|
dmsub = c.create_subkey(key, algorithm="rsa3072", expires_in=15768000,
|
||||||
encrypt = True)
|
encrypt=True)
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
As with the primary key, the results here can be checked with:
|
As with the primary key, the results here can be checked with:
|
||||||
@ -1206,38 +1214,66 @@
|
|||||||
:CUSTOM_ID: keygen-uids
|
:CUSTOM_ID: keygen-uids
|
||||||
:END:
|
:END:
|
||||||
|
|
||||||
By comparison to creating primary keys and subkeys, adding a new
|
|
||||||
user ID to an existing key is much simpler. The method used to do
|
|
||||||
this is =key_add_uid= and the only arguments it takes are for the
|
|
||||||
=key= and the new =uid=.
|
|
||||||
|
|
||||||
#+begin_src python
|
*** Adding User IDs
|
||||||
import gpg
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: keygen-uids-add
|
||||||
|
:END:
|
||||||
|
|
||||||
c = gpg.Context()
|
By comparison to creating primary keys and subkeys, adding a new
|
||||||
c.home_dir = "~/.gnupg-dm"
|
user ID to an existing key is much simpler. The method used to do
|
||||||
|
this is =key_add_uid= and the only arguments it takes are for the
|
||||||
|
=key= and the new =uid=.
|
||||||
|
|
||||||
dmfpr = "177B7C25DB99745EE2EE13ED026D2F19E99E63AA"
|
#+begin_src python
|
||||||
key = c.get_key(dmfpr, secret = True)
|
import gpg
|
||||||
uid = "Danger Mouse <danger.mouse@secret.example.net>"
|
|
||||||
|
|
||||||
c.key_add_uid(key, uid)
|
c = gpg.Context()
|
||||||
#+end_src
|
c.home_dir = "~/.gnupg-dm"
|
||||||
|
|
||||||
Unsurprisingly the result of this is:
|
dmfpr = "177B7C25DB99745EE2EE13ED026D2F19E99E63AA"
|
||||||
|
key = c.get_key(dmfpr, secret=True)
|
||||||
|
uid = "Danger Mouse <danger.mouse@secret.example.net>"
|
||||||
|
|
||||||
#+begin_src shell
|
c.key_add_uid(key, uid)
|
||||||
bash-4.4$ gpg --homedir ~/.gnupg-dm -K
|
#+end_src
|
||||||
~/.gnupg-dm/pubring.kbx
|
|
||||||
----------------------
|
|
||||||
sec rsa3072 2018-03-15 [SC] [expires: 2019-03-15]
|
|
||||||
177B7C25DB99745EE2EE13ED026D2F19E99E63AA
|
|
||||||
uid [ultimate] Danger Mouse <danger.mouse@secret.example.net>
|
|
||||||
uid [ultimate] Danger Mouse <dm@secret.example.net>
|
|
||||||
ssb rsa3072 2018-03-15 [E] [expires: 2018-09-13]
|
|
||||||
|
|
||||||
bash-4.4$
|
Unsurprisingly the result of this is:
|
||||||
#+end_src
|
|
||||||
|
#+begin_src shell
|
||||||
|
bash-4.4$ gpg --homedir ~/.gnupg-dm -K
|
||||||
|
~/.gnupg-dm/pubring.kbx
|
||||||
|
----------------------
|
||||||
|
sec rsa3072 2018-03-15 [SC] [expires: 2019-03-15]
|
||||||
|
177B7C25DB99745EE2EE13ED026D2F19E99E63AA
|
||||||
|
uid [ultimate] Danger Mouse <danger.mouse@secret.example.net>
|
||||||
|
uid [ultimate] Danger Mouse <dm@secret.example.net>
|
||||||
|
ssb rsa3072 2018-03-15 [E] [expires: 2018-09-13]
|
||||||
|
|
||||||
|
bash-4.4$
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*** Revokinging User IDs
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: keygen-uids-revoke
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Revoking a user ID is a fairly similar process, except that it
|
||||||
|
uses the =key_revoke_uid= method.
|
||||||
|
|
||||||
|
#+begin_src python
|
||||||
|
import gpg
|
||||||
|
|
||||||
|
c = gpg.Context()
|
||||||
|
c.home_dir = "~/.gnupg-dm"
|
||||||
|
|
||||||
|
dmfpr = "177B7C25DB99745EE2EE13ED026D2F19E99E63AA"
|
||||||
|
key = c.get_key(dmfpr, secret=True)
|
||||||
|
uid = "Danger Mouse <danger.mouse@secret.example.net>"
|
||||||
|
|
||||||
|
c.key_revoke_uid(key, uid)
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
** Key certification
|
** Key certification
|
||||||
@ -1251,8 +1287,8 @@
|
|||||||
The =key_sign= method takes four arguments: =key=, =uids=,
|
The =key_sign= method takes four arguments: =key=, =uids=,
|
||||||
=expires_in= and =local=. The default value of =uids= is =None=
|
=expires_in= and =local=. The default value of =uids= is =None=
|
||||||
and which results in all user IDs being selected. The default
|
and which results in all user IDs being selected. The default
|
||||||
values of =expires_in= and =local= is =False=; which results in the
|
value of both =expires_in= and =local= is =False=; which results in
|
||||||
signature never expiring and being able to be exported.
|
the signature never expiring and being able to be exported.
|
||||||
|
|
||||||
The =key= is the key being signed rather than the key doing the
|
The =key= is the key being signed rather than the key doing the
|
||||||
signing. To change the key doing the signing refer to the signing
|
signing. To change the key doing the signing refer to the signing
|
||||||
@ -1273,8 +1309,8 @@
|
|||||||
uid = "Danger Mouse <dm@secret.example.net>"
|
uid = "Danger Mouse <dm@secret.example.net>"
|
||||||
|
|
||||||
dmfpr = "177B7C25DB99745EE2EE13ED026D2F19E99E63AA"
|
dmfpr = "177B7C25DB99745EE2EE13ED026D2F19E99E63AA"
|
||||||
key = c.get_key(dmfpr, secret = True)
|
key = c.get_key(dmfpr, secret=True)
|
||||||
c.key_sign(key, uids = uid, expires_in = 2764800)
|
c.key_sign(key, uids=uid, expires_in=2764800)
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
62
lang/python/examples/howto/add-userid.py
Executable file
62
lang/python/examples/howto/add-userid.py
Executable file
@ -0,0 +1,62 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, unicode_literals
|
||||||
|
|
||||||
|
# Copyright (C) 2018 Ben McGinnes <ben@gnupg.org>
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU General Public License as published by the Free Software
|
||||||
|
# Foundation; either version 2 of the License, or (at your option) any later
|
||||||
|
# version.
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU Lesser General Public License as published by the Free
|
||||||
|
# Software Foundation; either version 2.1 of the License, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License and the GNU
|
||||||
|
# Lesser General Public Licensefor more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License and the GNU
|
||||||
|
# Lesser General Public along with this program; if not, see
|
||||||
|
# <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import gpg
|
||||||
|
import os.path
|
||||||
|
|
||||||
|
print("""
|
||||||
|
This script adds a new user ID to an existing key.
|
||||||
|
|
||||||
|
The gpg-agent and pinentry are invoked to enter the passphrase.
|
||||||
|
""")
|
||||||
|
|
||||||
|
c = gpg.Context()
|
||||||
|
|
||||||
|
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||||
|
fpr0 = input("Enter the fingerprint of the key to modify: ")
|
||||||
|
uid_name = input("Enter the name of the user ID: ")
|
||||||
|
uid_email = input("Enter the email address of the user ID: ")
|
||||||
|
uid_cmnt = input("Enter a comment to include (optional): ")
|
||||||
|
|
||||||
|
if homedir.startswith("~"):
|
||||||
|
if os.path.exists(os.path.expanduser(homedir)) is True:
|
||||||
|
c.home_dir = os.path.expanduser(homedir)
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
elif os.path.exists(homedir) is True:
|
||||||
|
c.home_dir = homedir
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
fpr = "".join(fpr0.split())
|
||||||
|
|
||||||
|
if len(uid_cmnt) > 0:
|
||||||
|
userid = "{0} ({1}) <{2}>".format(uid_name, uid_cmnt, uid_email)
|
||||||
|
else:
|
||||||
|
userid = "{0} <{2}>".format(uid_name, uid_email)
|
||||||
|
|
||||||
|
key = c.get_key(fpr, secret=True)
|
||||||
|
c.key_add_uid(key, userid)
|
95
lang/python/examples/howto/create-key.py
Executable file
95
lang/python/examples/howto/create-key.py
Executable file
@ -0,0 +1,95 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, unicode_literals
|
||||||
|
|
||||||
|
# Copyright (C) 2018 Ben McGinnes <ben@gnupg.org>
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU General Public License as published by the Free Software
|
||||||
|
# Foundation; either version 2 of the License, or (at your option) any later
|
||||||
|
# version.
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU Lesser General Public License as published by the Free
|
||||||
|
# Software Foundation; either version 2.1 of the License, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License and the GNU
|
||||||
|
# Lesser General Public Licensefor more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License and the GNU
|
||||||
|
# Lesser General Public along with this program; if not, see
|
||||||
|
# <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import gpg
|
||||||
|
import os.path
|
||||||
|
|
||||||
|
print("""
|
||||||
|
This script generates a new key which does not expire.
|
||||||
|
|
||||||
|
The gpg-agent and pinentry are invoked to set the passphrase.
|
||||||
|
""")
|
||||||
|
|
||||||
|
c = gpg.Context()
|
||||||
|
|
||||||
|
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||||
|
uid_name = input("Enter the name of the user ID: ")
|
||||||
|
uid_email = input("Enter the email address of the user ID: ")
|
||||||
|
uid_cmnt = input("Enter a comment to include (optional): ")
|
||||||
|
key_algo = input("Enter the key algorithm, RSA or DSA (default is RSA): ")
|
||||||
|
key_size = input("Enter the key size (2048-4096, default is 2048): ")
|
||||||
|
|
||||||
|
if homedir.startswith("~"):
|
||||||
|
if os.path.exists(os.path.expanduser(homedir)) is True:
|
||||||
|
c.home_dir = os.path.expanduser(homedir)
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
elif os.path.exists(homedir) is True:
|
||||||
|
c.home_dir = homedir
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if len(uid_cmnt) > 0:
|
||||||
|
userid = "{0} ({1}) <{2}>".format(uid_name, uid_cmnt, uid_email)
|
||||||
|
else:
|
||||||
|
userid = "{0} <{2}>".format(uid_name, uid_email)
|
||||||
|
|
||||||
|
if key_algo.lower() == "dsa":
|
||||||
|
ka = "dsa"
|
||||||
|
else:
|
||||||
|
ka = "rsa"
|
||||||
|
|
||||||
|
if len(key_size) == 4:
|
||||||
|
try:
|
||||||
|
ks0 = int(key_size)
|
||||||
|
except ValueError:
|
||||||
|
ks0 = None
|
||||||
|
if ks0 is None:
|
||||||
|
ks = "2048"
|
||||||
|
else:
|
||||||
|
if ks0 < 2048:
|
||||||
|
ks = "2048"
|
||||||
|
elif ka == "dsa" and ks0 > 3072:
|
||||||
|
ks = "3072"
|
||||||
|
elif ka == "rsa" and ks0 > 4096:
|
||||||
|
ks = "4096"
|
||||||
|
else:
|
||||||
|
ks = key_size
|
||||||
|
else:
|
||||||
|
ks = "2048"
|
||||||
|
|
||||||
|
keyalgo = "{0}{1}".format(ka, ks)
|
||||||
|
|
||||||
|
newkey = c.create_key(userid, algorithm=keyalgo, expires=False,
|
||||||
|
passphrase=True, certify=True)
|
||||||
|
key = c.get_key(newkey.fpr, secret=True)
|
||||||
|
|
||||||
|
if ka == "rsa":
|
||||||
|
newsub = c.create_subkey(key, algorithm=keyalgo, expires=False,
|
||||||
|
passphrase=True, encrypt=True)
|
||||||
|
else:
|
||||||
|
newsub = c.create_subkey(key, expires=False, passphrase=True,
|
||||||
|
encrypt=True)
|
62
lang/python/examples/howto/revoke-userid.py
Executable file
62
lang/python/examples/howto/revoke-userid.py
Executable file
@ -0,0 +1,62 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, unicode_literals
|
||||||
|
|
||||||
|
# Copyright (C) 2018 Ben McGinnes <ben@gnupg.org>
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU General Public License as published by the Free Software
|
||||||
|
# Foundation; either version 2 of the License, or (at your option) any later
|
||||||
|
# version.
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU Lesser General Public License as published by the Free
|
||||||
|
# Software Foundation; either version 2.1 of the License, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License and the GNU
|
||||||
|
# Lesser General Public Licensefor more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License and the GNU
|
||||||
|
# Lesser General Public along with this program; if not, see
|
||||||
|
# <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import gpg
|
||||||
|
import os.path
|
||||||
|
|
||||||
|
print("""
|
||||||
|
This script revokes a user ID on an existing key.
|
||||||
|
|
||||||
|
The gpg-agent and pinentry are invoked to enter the passphrase.
|
||||||
|
""")
|
||||||
|
|
||||||
|
c = gpg.Context()
|
||||||
|
|
||||||
|
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||||
|
fpr0 = input("Enter the fingerprint of the key to modify: ")
|
||||||
|
uid_name = input("Enter the name of the user ID: ")
|
||||||
|
uid_email = input("Enter the email address of the user ID: ")
|
||||||
|
uid_cmnt = input("Enter a comment to include (optional): ")
|
||||||
|
|
||||||
|
if homedir.startswith("~"):
|
||||||
|
if os.path.exists(os.path.expanduser(homedir)) is True:
|
||||||
|
c.home_dir = os.path.expanduser(homedir)
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
elif os.path.exists(homedir) is True:
|
||||||
|
c.home_dir = homedir
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
fpr = "".join(fpr0.split())
|
||||||
|
|
||||||
|
if len(uid_cmnt) > 0:
|
||||||
|
userid = "{0} ({1}) <{2}>".format(uid_name, uid_cmnt, uid_email)
|
||||||
|
else:
|
||||||
|
userid = "{0} <{2}>".format(uid_name, uid_email)
|
||||||
|
|
||||||
|
key = c.get_key(fpr, secret=True)
|
||||||
|
c.key_revoke_uid(key, userid)
|
63
lang/python/examples/howto/sign-key.py
Executable file
63
lang/python/examples/howto/sign-key.py
Executable file
@ -0,0 +1,63 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, unicode_literals
|
||||||
|
|
||||||
|
# Copyright (C) 2018 Ben McGinnes <ben@gnupg.org>
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU General Public License as published by the Free Software
|
||||||
|
# Foundation; either version 2 of the License, or (at your option) any later
|
||||||
|
# version.
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU Lesser General Public License as published by the Free
|
||||||
|
# Software Foundation; either version 2.1 of the License, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License and the GNU
|
||||||
|
# Lesser General Public Licensefor more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License and the GNU
|
||||||
|
# Lesser General Public along with this program; if not, see
|
||||||
|
# <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import gpg
|
||||||
|
import os.path
|
||||||
|
|
||||||
|
print("""
|
||||||
|
This script signs or certifies a key.
|
||||||
|
|
||||||
|
The gpg-agent and pinentry are invoked to enter the passphrase.
|
||||||
|
""")
|
||||||
|
|
||||||
|
c = gpg.Context()
|
||||||
|
|
||||||
|
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||||
|
fpr0 = input("Enter the fingerprint of the key to sign: ")
|
||||||
|
userid = input("Enter the UID to sign (case sensitive, optional): ")
|
||||||
|
sig_type = input("Enter the certification type (local or normal): ")
|
||||||
|
|
||||||
|
if homedir.startswith("~"):
|
||||||
|
if os.path.exists(os.path.expanduser(homedir)) is True:
|
||||||
|
c.home_dir = os.path.expanduser(homedir)
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
elif os.path.exists(homedir) is True:
|
||||||
|
c.home_dir = homedir
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
fpr = "".join(fpr0.split())
|
||||||
|
key = c.get_key(fpr, secret=False)
|
||||||
|
|
||||||
|
if len(userid) > 0 and sig_type.lower() == "local":
|
||||||
|
c.key_sign(key, uids=userid, local=True)
|
||||||
|
elif len(userid) > 0 and sig_type.lower() != "local":
|
||||||
|
c.key_sign(key, uids=userid)
|
||||||
|
elif len(userid) == 0 and sig_type.lower() == "local":
|
||||||
|
c.key_sign(key, local=True)
|
||||||
|
else:
|
||||||
|
c.key_sign(key)
|
126
lang/python/examples/howto/temp-homedir-config.py
Executable file
126
lang/python/examples/howto/temp-homedir-config.py
Executable file
@ -0,0 +1,126 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, unicode_literals
|
||||||
|
|
||||||
|
# Copyright (C) 2018 Ben McGinnes <ben@gnupg.org>
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU General Public License as published by the Free Software
|
||||||
|
# Foundation; either version 2 of the License, or (at your option) any later
|
||||||
|
# version.
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU Lesser General Public License as published by the Free
|
||||||
|
# Software Foundation; either version 2.1 of the License, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License and the GNU
|
||||||
|
# Lesser General Public Licensefor more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License and the GNU
|
||||||
|
# Lesser General Public along with this program; if not, see
|
||||||
|
# <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import os
|
||||||
|
import os.path
|
||||||
|
import sys
|
||||||
|
|
||||||
|
intro = """
|
||||||
|
This script creates a temporary directory to use as a homedir for
|
||||||
|
testing key generation tasks with the correct permissions, along
|
||||||
|
with a gpg.conf file containing the same configuration options
|
||||||
|
listed in the HOWTO.
|
||||||
|
|
||||||
|
You may wish to change the order of the cipher preferences or
|
||||||
|
remove those not relevant to your installation. These
|
||||||
|
configuration parameters assume that all ciphers and digests are
|
||||||
|
installed and available rather than limiting to the default
|
||||||
|
ciphers and digests.
|
||||||
|
|
||||||
|
The script prompts for a directory name to be installed as a hidden
|
||||||
|
directory in the user's home directory on POSIX systems. So if you
|
||||||
|
enter "gnupg-temp" on a Linux, BSD or OS X system, it will create
|
||||||
|
"~/.gnupg-temp" (you do not need to enter the leading dot).
|
||||||
|
|
||||||
|
This script has not been tested on Windows systems and may have
|
||||||
|
unpredictable results. That said, it will not delete or copy over
|
||||||
|
existing data.
|
||||||
|
|
||||||
|
If the directory already exists, the script will terminate with a
|
||||||
|
message telling you to specify a new directory name. There is no
|
||||||
|
default directory name.
|
||||||
|
"""
|
||||||
|
|
||||||
|
gpgconf = """# gpg.conf settings for key generation:
|
||||||
|
expert
|
||||||
|
allow-freeform-uid
|
||||||
|
allow-secret-key-import
|
||||||
|
trust-model tofu+pgp
|
||||||
|
tofu-default-policy unknown
|
||||||
|
enable-large-rsa
|
||||||
|
enable-dsa2
|
||||||
|
cert-digest-algo SHA512
|
||||||
|
default-preference-list TWOFISH CAMELLIA256 AES256 CAMELLIA192 AES192 CAMELLIA128 AES BLOWFISH IDEA CAST5 3DES SHA512 SHA384 SHA256 SHA224 RIPEMD160 SHA1 ZLIB BZIP2 ZIP Uncompressed
|
||||||
|
personal-cipher-preferences TWOFISH CAMELLIA256 AES256 CAMELLIA192 AES192 CAMELLIA128 AES BLOWFISH IDEA CAST5 3DES
|
||||||
|
personal-digest-preferences SHA512 SHA384 SHA256 SHA224 RIPEMD160 SHA1
|
||||||
|
personal-compress-preferences ZLIB BZIP2 ZIP Uncompressed
|
||||||
|
"""
|
||||||
|
|
||||||
|
agentconf = """# gpg-agent.conf settings for key generation:
|
||||||
|
default-cache-ttl 300
|
||||||
|
"""
|
||||||
|
|
||||||
|
if len(sys.argv) == 1:
|
||||||
|
print(intro)
|
||||||
|
new_homedir = input("Enter the temporary gnupg homedir name: ")
|
||||||
|
elif len(sys.argv) == 2:
|
||||||
|
new_homedir = sys.argv[1]
|
||||||
|
else:
|
||||||
|
new_homedir = " ".join(sys.argv[1:])
|
||||||
|
|
||||||
|
userdir = os.path.expanduser("~")
|
||||||
|
|
||||||
|
if new_homedir.startswith("~"):
|
||||||
|
new_homdir.replace("~", "")
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if new_homedir.startswith("/"):
|
||||||
|
new_homdir.replace("/", "")
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if new_homedir.startswith("."):
|
||||||
|
new_homdir.replace(".", "_")
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if new_homedir.count(" ") > 0:
|
||||||
|
new_homedir.replace(" ", "_")
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
nh = "{0}/.{1}".format(userdir, new_homedir)
|
||||||
|
|
||||||
|
if os.path.exists(nh) is True:
|
||||||
|
print("The {0} directory already exists.".format(nh))
|
||||||
|
else:
|
||||||
|
print("Creating the {0} directory.".format(nh))
|
||||||
|
os.mkdir(nh)
|
||||||
|
os.chmod(nh, 0o700)
|
||||||
|
with open("{0}/{1}".format(nh, "gpg.conf"), "w") as f1:
|
||||||
|
f1.write(gpgconf)
|
||||||
|
os.chmod("{0}/{1}".format(nh, "gpg.conf"), 0o600)
|
||||||
|
with open("{0}/{1}".format(nh, "gpg-agent.conf"), "w") as f2:
|
||||||
|
f2.write(gpgconf)
|
||||||
|
os.chmod("{0}/{1}".format(nh, "gpg-agent.conf"), 0o600)
|
||||||
|
print("""You may now use the {0} directory as an alternative GPG homedir:
|
||||||
|
|
||||||
|
gpg --homedir {0}
|
||||||
|
gpg --homedir --full-gen-key
|
||||||
|
|
||||||
|
Or with GPGME scripts, including the GPGME Python bindings.
|
||||||
|
""")
|
@ -41,6 +41,10 @@
|
|||||||
#include "cJSON.h"
|
#include "cJSON.h"
|
||||||
|
|
||||||
|
|
||||||
|
#if GPGRT_VERSION_NUMBER < 0x011c00 /* 1.28 */
|
||||||
|
int main (void){fputs ("Build with Libgpg-error >= 1.28!\n", stderr);return 1;}
|
||||||
|
#else /* libgpg-error >= 1.28 */
|
||||||
|
|
||||||
/* We don't allow a request with more than 64 MiB. */
|
/* We don't allow a request with more than 64 MiB. */
|
||||||
#define MAX_REQUEST_SIZE (64 * 1024 * 1024)
|
#define MAX_REQUEST_SIZE (64 * 1024 * 1024)
|
||||||
|
|
||||||
@ -56,7 +60,8 @@ static char *error_object_string (const char *message,
|
|||||||
|
|
||||||
/* True if interactive mode is active. */
|
/* True if interactive mode is active. */
|
||||||
static int opt_interactive;
|
static int opt_interactive;
|
||||||
|
/* True is debug mode is active. */
|
||||||
|
static int opt_debug;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -754,7 +759,7 @@ op_help (cjson_t request, cjson_t result)
|
|||||||
|
|
||||||
|
|
||||||
/* Process a request and return the response. The response is a newly
|
/* Process a request and return the response. The response is a newly
|
||||||
* allocated staring or NULL in case of an error. */
|
* allocated string or NULL in case of an error. */
|
||||||
static char *
|
static char *
|
||||||
process_request (const char *request)
|
process_request (const char *request)
|
||||||
{
|
{
|
||||||
@ -845,7 +850,6 @@ process_request (const char *request)
|
|||||||
|
|
||||||
leave:
|
leave:
|
||||||
cJSON_Delete (json);
|
cJSON_Delete (json);
|
||||||
json = NULL;
|
|
||||||
if (opt_interactive)
|
if (opt_interactive)
|
||||||
res = cJSON_Print (response);
|
res = cJSON_Print (response);
|
||||||
else
|
else
|
||||||
@ -1072,7 +1076,7 @@ interactive_repl (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Read and process asingle request. */
|
/* Read and process a single request. */
|
||||||
static void
|
static void
|
||||||
read_and_process_single_request (void)
|
read_and_process_single_request (void)
|
||||||
{
|
{
|
||||||
@ -1126,6 +1130,7 @@ native_messaging_repl (void)
|
|||||||
* binary mode. */
|
* binary mode. */
|
||||||
es_set_binary (es_stdin);
|
es_set_binary (es_stdin);
|
||||||
es_set_binary (es_stdout);
|
es_set_binary (es_stdout);
|
||||||
|
es_setbuf (es_stdin, NULL); /* stdin needs to be unbuffered! */
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
@ -1149,7 +1154,7 @@ native_messaging_repl (void)
|
|||||||
{
|
{
|
||||||
log_error ("error reading request: request too long (%zu MiB)\n",
|
log_error ("error reading request: request too long (%zu MiB)\n",
|
||||||
(size_t)nrequest / (1024*1024));
|
(size_t)nrequest / (1024*1024));
|
||||||
/* Fixme: Shall we read the request t the bit bucket and
|
/* Fixme: Shall we read the request to the bit bucket and
|
||||||
* return an error reponse or just return an error reponse
|
* return an error reponse or just return an error reponse
|
||||||
* and terminate? Needs some testing. */
|
* and terminate? Needs some testing. */
|
||||||
break;
|
break;
|
||||||
@ -1181,8 +1186,12 @@ native_messaging_repl (void)
|
|||||||
}
|
}
|
||||||
else /* Process request */
|
else /* Process request */
|
||||||
{
|
{
|
||||||
|
if (opt_debug)
|
||||||
|
log_debug ("request='%s'\n", request);
|
||||||
xfree (response);
|
xfree (response);
|
||||||
response = process_request (request);
|
response = process_request (request);
|
||||||
|
if (opt_debug)
|
||||||
|
log_debug ("response='%s'\n", response);
|
||||||
}
|
}
|
||||||
nresponse = strlen (response);
|
nresponse = strlen (response);
|
||||||
|
|
||||||
@ -1263,12 +1272,18 @@ main (int argc, char *argv[])
|
|||||||
enum { CMD_DEFAULT = 0,
|
enum { CMD_DEFAULT = 0,
|
||||||
CMD_INTERACTIVE = 'i',
|
CMD_INTERACTIVE = 'i',
|
||||||
CMD_SINGLE = 's',
|
CMD_SINGLE = 's',
|
||||||
CMD_LIBVERSION = 501
|
CMD_LIBVERSION = 501,
|
||||||
} cmd = CMD_DEFAULT;
|
} cmd = CMD_DEFAULT;
|
||||||
|
enum {
|
||||||
|
OPT_DEBUG = 600
|
||||||
|
};
|
||||||
|
|
||||||
static gpgrt_opt_t opts[] = {
|
static gpgrt_opt_t opts[] = {
|
||||||
ARGPARSE_c (CMD_INTERACTIVE, "interactive", "Interactive REPL"),
|
ARGPARSE_c (CMD_INTERACTIVE, "interactive", "Interactive REPL"),
|
||||||
ARGPARSE_c (CMD_SINGLE, "single", "Single request mode"),
|
ARGPARSE_c (CMD_SINGLE, "single", "Single request mode"),
|
||||||
ARGPARSE_c (CMD_LIBVERSION, "lib-version", "Show library version"),
|
ARGPARSE_c (CMD_LIBVERSION, "lib-version", "Show library version"),
|
||||||
|
ARGPARSE_s_n(OPT_DEBUG, "debug", "Flyswatter"),
|
||||||
|
|
||||||
ARGPARSE_end()
|
ARGPARSE_end()
|
||||||
};
|
};
|
||||||
gpgrt_argparse_t pargs = { &argc, &argv};
|
gpgrt_argparse_t pargs = { &argc, &argv};
|
||||||
@ -1298,6 +1313,8 @@ main (int argc, char *argv[])
|
|||||||
cmd = pargs.r_opt;
|
cmd = pargs.r_opt;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OPT_DEBUG: opt_debug = 1; break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
pargs.err = ARGPARSE_PRINT_WARNING;
|
pargs.err = ARGPARSE_PRINT_WARNING;
|
||||||
break;
|
break;
|
||||||
@ -1305,6 +1322,29 @@ main (int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
gpgrt_argparse (NULL, &pargs, NULL);
|
gpgrt_argparse (NULL, &pargs, NULL);
|
||||||
|
|
||||||
|
if (!opt_debug)
|
||||||
|
{
|
||||||
|
const char *s = getenv ("GPGME_JSON_DEBUG");
|
||||||
|
if (s && atoi (s) > 0)
|
||||||
|
opt_debug = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opt_debug)
|
||||||
|
{
|
||||||
|
const char *home = getenv ("HOME");
|
||||||
|
char *file = xstrconcat ("socket://",
|
||||||
|
home? home:"/tmp",
|
||||||
|
"/.gnupg/S.gpgme-json.log", NULL);
|
||||||
|
log_set_file (file);
|
||||||
|
xfree (file);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opt_debug)
|
||||||
|
{ int i;
|
||||||
|
for (i=0; argv[i]; i++)
|
||||||
|
log_debug ("argv[%d]='%s'\n", i, argv[i]);
|
||||||
|
}
|
||||||
|
|
||||||
switch (cmd)
|
switch (cmd)
|
||||||
{
|
{
|
||||||
case CMD_DEFAULT:
|
case CMD_DEFAULT:
|
||||||
@ -1327,6 +1367,10 @@ main (int argc, char *argv[])
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (opt_debug)
|
||||||
|
log_debug ("ready");
|
||||||
|
|
||||||
#endif /* This is a modern libgp-error. */
|
#endif /* This is a modern libgp-error. */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif /* libgpg-error >= 1.28 */
|
||||||
|
@ -1269,6 +1269,8 @@ gpgme_get_key (gpgme_ctx_t ctx, const char *fpr, gpgme_key_t *r_key,
|
|||||||
if (!ctx || !r_key || !fpr)
|
if (!ctx || !r_key || !fpr)
|
||||||
return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
|
return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
|
||||||
|
|
||||||
|
*r_key = NULL;
|
||||||
|
|
||||||
if (strlen (fpr) < 8) /* We have at least a key ID. */
|
if (strlen (fpr) < 8) /* We have at least a key ID. */
|
||||||
return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
|
return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user