Patches for M2Crypto 0.09
Toby Allsopp <[email protected]>
| Newsgroups | gmane.comp.python.cryptography |
|---|---|
| Message-ID | <20030214055925.GA9813@candyboy> |
Hi. Attached are two patches against M2Crypto 0.09. The first makes it build against OpenSSL 0.9.7. It basically just makes some things const. The second adds a few functions that make it possible to create a very basic certificate request (no extensions yet). I've included a really crap unit test for it too (that I've copied the copyright notice from the other tests for -- I have no interest in claiming the copyright on it). Hopefully this will be useful to someone else. It would also be nice if these could be included in the next version (makes my life easier :-). Regards, Toby.
m2crypto-0.09-openssl0.9.7.patch
(text/plain, 9.6 KB)
diff -ru m2crypto-0.09/setup.py m2crypto-0.09-toby/setup.py
--- m2crypto-0.09/setup.py 2003-01-08 05:43:54.000000000 +1300
+++ m2crypto-0.09-toby/setup.py 2003-01-21 20:44:16.000000000 +1300
@@ -35,7 +35,7 @@
)
setup(name = 'M2Crypto',
- version = '0.08',
+ version = '0.09',
description = 'M2Crypto: A Python interface to OpenSSL',
author = 'Ng Pheng Siong',
author_email = '[email protected]',
diff -ru m2crypto-0.09/swig/_dh.i m2crypto-0.09-toby/swig/_dh.i
--- m2crypto-0.09/swig/_dh.i 2002-12-23 17:51:21.000000000 +1300
+++ m2crypto-0.09-toby/swig/_dh.i 2003-02-10 20:30:31.000000000 +1300
@@ -13,9 +13,9 @@
%name(dh_new) extern DH *DH_new(void);
%name(dh_free) extern void DH_free(DH *);
-%name(dh_size) extern int DH_size(DH *);
+%name(dh_size) extern int DH_size(const DH *);
%name(dh_generate_key) extern int DH_generate_key(DH *);
-%name(dhparams_print) extern int DHparams_print(BIO *, DH *);
+%name(dhparams_print) extern int DHparams_print(BIO *, const DH *);
%constant int dh_check_ok = 0;
%constant int dh_check_p_not_prime = DH_CHECK_P_NOT_PRIME;
diff -ru m2crypto-0.09/swig/_dsa.i m2crypto-0.09-toby/swig/_dsa.i
--- m2crypto-0.09/swig/_dsa.i 2001-09-18 18:22:12.000000000 +1200
+++ m2crypto-0.09-toby/swig/_dsa.i 2003-02-10 20:31:14.000000000 +1300
@@ -20,7 +20,7 @@
%name(dsa_new) extern DSA *DSA_new(void);
%name(dsa_free) extern void DSA_free(DSA *);
-%name(dsa_size) extern int DSA_size(DSA *); /* assert(dsa->q); */
+%name(dsa_size) extern int DSA_size(const DSA *); /* assert(dsa->q); */
%name(dsa_gen_key) extern int DSA_generate_key(DSA *);
%inline %{
diff -ru m2crypto-0.09/swig/_evp.i m2crypto-0.09-toby/swig/_evp.i
--- m2crypto-0.09/swig/_evp.i 2002-12-23 17:51:57.000000000 +1300
+++ m2crypto-0.09-toby/swig/_evp.i 2003-02-12 18:17:54.000000000 +1300
@@ -15,47 +15,47 @@
%apply Pointer NONNULL { EVP_CIPHER_CTX * };
%apply Pointer NONNULL { EVP_CIPHER * };
-%name(md5) extern EVP_MD *EVP_md5(void);
-%name(sha1) extern EVP_MD *EVP_sha1(void);
-%name(ripemd160) extern EVP_MD *EVP_ripemd160(void);
-%name(digest_init) extern void EVP_DigestInit(EVP_MD_CTX *, const EVP_MD *);
-
-%name(des_ecb) extern EVP_CIPHER *EVP_des_ecb(void);
-%name(des_ede_ecb) extern EVP_CIPHER *EVP_des_ede(void);
-%name(des_ede3_ecb) extern EVP_CIPHER *EVP_des_ede3(void);
-%name(des_cbc) extern EVP_CIPHER *EVP_des_cbc(void);
-%name(des_ede_cbc) extern EVP_CIPHER *EVP_des_ede_cbc(void);
-%name(des_ede3_cbc) extern EVP_CIPHER *EVP_des_ede3_cbc(void);
-%name(des_cfb) extern EVP_CIPHER *EVP_des_cfb(void);
-%name(des_ede_cfb) extern EVP_CIPHER *EVP_des_ede_cfb(void);
-%name(des_ede3_cfb) extern EVP_CIPHER *EVP_des_ede3_cfb(void);
-%name(des_ofb) extern EVP_CIPHER *EVP_des_ofb(void);
-%name(des_ede_ofb) extern EVP_CIPHER *EVP_des_ede_ofb(void);
-%name(des_ede3_ofb) extern EVP_CIPHER *EVP_des_ede3_ofb(void);
-%name(bf_ecb) extern EVP_CIPHER *EVP_bf_ecb(void);
-%name(bf_cbc) extern EVP_CIPHER *EVP_bf_cbc(void);
-%name(bf_cfb) extern EVP_CIPHER *EVP_bf_cfb(void);
-%name(bf_ofb) extern EVP_CIPHER *EVP_bf_ofb(void);
-/*
-%name(idea_ecb) extern EVP_CIPHER *EVP_idea_ecb(void);
-%name(idea_cbc) extern EVP_CIPHER *EVP_idea_cbc(void);
-%name(idea_cfb) extern EVP_CIPHER *EVP_idea_cfb(void);
-%name(idea_ofb) extern EVP_CIPHER *EVP_idea_ofb(void);
-*/
-%name(cast5_ecb) extern EVP_CIPHER *EVP_cast5_ecb(void);
-%name(cast5_cbc) extern EVP_CIPHER *EVP_cast5_cbc(void);
-%name(cast5_cfb) extern EVP_CIPHER *EVP_cast5_cfb(void);
-%name(cast5_ofb) extern EVP_CIPHER *EVP_cast5_ofb(void);
-%name(rc5_ecb) extern EVP_CIPHER *EVP_rc5_32_12_16_ecb(void);
-%name(rc5_cbc) extern EVP_CIPHER *EVP_rc5_32_12_16_cbc(void);
-%name(rc5_cfb) extern EVP_CIPHER *EVP_rc5_32_12_16_cfb(void);
-%name(rc5_ofb) extern EVP_CIPHER *EVP_rc5_32_12_16_ofb(void);
-%name(rc4) extern EVP_CIPHER *EVP_rc4(void);
-%name(rc2_40_cbc) extern EVP_CIPHER *EVP_rc2_40_cbc(void);
+%name(md5) extern const EVP_MD *EVP_md5(void);
+%name(sha1) extern const EVP_MD *EVP_sha1(void);
+%name(ripemd160) extern const EVP_MD *EVP_ripemd160(void);
+%name(digest_init) extern int EVP_DigestInit(EVP_MD_CTX *, const EVP_MD *);
+
+%name(des_ecb) extern const EVP_CIPHER *EVP_des_ecb(void);
+%name(des_ede_ecb) extern const EVP_CIPHER *EVP_des_ede(void);
+%name(des_ede3_ecb) extern const EVP_CIPHER *EVP_des_ede3(void);
+%name(des_cbc) extern const EVP_CIPHER *EVP_des_cbc(void);
+%name(des_ede_cbc) extern const EVP_CIPHER *EVP_des_ede_cbc(void);
+%name(des_ede3_cbc) extern const EVP_CIPHER *EVP_des_ede3_cbc(void);
+%name(des_cfb) extern const EVP_CIPHER *EVP_des_cfb(void);
+%name(des_ede_cfb) extern const EVP_CIPHER *EVP_des_ede_cfb(void);
+%name(des_ede3_cfb) extern const EVP_CIPHER *EVP_des_ede3_cfb(void);
+%name(des_ofb) extern const EVP_CIPHER *EVP_des_ofb(void);
+%name(des_ede_ofb) extern const EVP_CIPHER *EVP_des_ede_ofb(void);
+%name(des_ede3_ofb) extern const EVP_CIPHER *EVP_des_ede3_ofb(void);
+%name(bf_ecb) extern const EVP_CIPHER *EVP_bf_ecb(void);
+%name(bf_cbc) extern const EVP_CIPHER *EVP_bf_cbc(void);
+%name(bf_cfb) extern const EVP_CIPHER *EVP_bf_cfb(void);
+%name(bf_ofb) extern const EVP_CIPHER *EVP_bf_ofb(void);
+/*
+%name(idea_ecb) extern const EVP_CIPHER *EVP_idea_ecb(void);
+%name(idea_cbc) extern const EVP_CIPHER *EVP_idea_cbc(void);
+%name(idea_cfb) extern const EVP_CIPHER *EVP_idea_cfb(void);
+%name(idea_ofb) extern const EVP_CIPHER *EVP_idea_ofb(void);
+*/
+%name(cast5_ecb) extern const EVP_CIPHER *EVP_cast5_ecb(void);
+%name(cast5_cbc) extern const EVP_CIPHER *EVP_cast5_cbc(void);
+%name(cast5_cfb) extern const EVP_CIPHER *EVP_cast5_cfb(void);
+%name(cast5_ofb) extern const EVP_CIPHER *EVP_cast5_ofb(void);
+%name(rc5_ecb) extern const EVP_CIPHER *EVP_rc5_32_12_16_ecb(void);
+%name(rc5_cbc) extern const EVP_CIPHER *EVP_rc5_32_12_16_cbc(void);
+%name(rc5_cfb) extern const EVP_CIPHER *EVP_rc5_32_12_16_cfb(void);
+%name(rc5_ofb) extern const EVP_CIPHER *EVP_rc5_32_12_16_ofb(void);
+%name(rc4) extern const EVP_CIPHER *EVP_rc4(void);
+%name(rc2_40_cbc) extern const EVP_CIPHER *EVP_rc2_40_cbc(void);
%name(pkey_new) extern EVP_PKEY *EVP_PKEY_new(void);
%name(pkey_free) extern void EVP_PKEY_free(EVP_PKEY *);
-%name(sign_init) extern void EVP_SignInit(EVP_MD_CTX *, const EVP_MD *);
+%name(sign_init) extern int EVP_SignInit(EVP_MD_CTX *, const EVP_MD *);
%inline %{
#define PKCS5_SALT_LEN 8
diff -ru m2crypto-0.09/swig/_lib.h m2crypto-0.09-toby/swig/_lib.h
--- m2crypto-0.09/swig/_lib.h 2002-12-23 17:52:18.000000000 +1300
+++ m2crypto-0.09-toby/swig/_lib.h 2003-02-10 20:17:58.000000000 +1300
@@ -13,5 +13,5 @@
void gen_callback(int p, int n, void *arg);
int passphrase_callback(char *buf, int num, int v, void *userdata);
-void lib_init();
+void lib_init(void);
diff -ru m2crypto-0.09/swig/_lib.i m2crypto-0.09-toby/swig/_lib.i
--- m2crypto-0.09/swig/_lib.i 2002-12-23 17:52:35.000000000 +1300
+++ m2crypto-0.09-toby/swig/_lib.i 2003-02-10 20:22:43.000000000 +1300
@@ -4,7 +4,6 @@
%{
#include <openssl/err.h>
#include <openssl/evp.h>
-#include <openssl/e_os.h>
#include <openssl/ssl.h>
#include <ceval.h>
@@ -76,7 +75,7 @@
/* C callbacks invoked by OpenSSL; these in turn call back into
Python. */
-int MS_CALLBACK ssl_verify_callback(int ok, X509_STORE_CTX *ctx) {
+int ssl_verify_callback(int ok, X509_STORE_CTX *ctx) {
PyObject *argv, *ret, *_x509, *_ssl_ctx;
X509 *x509;
SSL *ssl;
@@ -115,7 +114,7 @@
return cret;
}
-void MS_CALLBACK ssl_info_callback(SSL *s, int where, int ret) {
+void ssl_info_callback(SSL *s, int where, int ret) {
PyObject *argv, *retval, *_SSL;
PyThreadState *_save;
Only in m2crypto-0.09-toby/swig: _m2crypto.c
Only in m2crypto-0.09-toby/swig: _m2crypto.py
Only in m2crypto-0.09-toby/swig: _m2crypto_wrap.c
diff -ru m2crypto-0.09/swig/_rsa.i m2crypto-0.09-toby/swig/_rsa.i
--- m2crypto-0.09/swig/_rsa.i 2002-12-23 17:53:53.000000000 +1300
+++ m2crypto-0.09-toby/swig/_rsa.i 2003-02-10 20:30:50.000000000 +1300
@@ -13,8 +13,8 @@
%name(rsa_new) extern RSA *RSA_new(void);
%name(rsa_free) extern void RSA_free(RSA *);
-%name(rsa_size) extern int RSA_size(RSA *);
-%name(rsa_check_key) extern int RSA_check_key(RSA *);
+%name(rsa_size) extern int RSA_size(const RSA *);
+%name(rsa_check_key) extern int RSA_check_key(const RSA *);
%constant int no_padding = RSA_NO_PADDING;
%constant int pkcs1_padding = RSA_PKCS1_PADDING;
diff -ru m2crypto-0.09/swig/_ssl.i m2crypto-0.09-toby/swig/_ssl.i
--- m2crypto-0.09/swig/_ssl.i 2002-12-23 17:54:12.000000000 +1300
+++ m2crypto-0.09-toby/swig/_ssl.i 2003-02-10 20:41:07.000000000 +1300
@@ -17,12 +17,12 @@
%apply Pointer NONNULL { PyObject *pyfunc };
%name(ssl_get_error) extern int SSL_get_error(SSL *, int);
-%name(ssl_get_state) extern char *SSL_state_string(SSL *);
-%name(ssl_get_state_v) extern char *SSL_state_string_long(SSL *);
-%name(ssl_get_alert_type) extern char *SSL_alert_type_string(int);
-%name(ssl_get_alert_type_v) extern char *SSL_alert_type_string_long(int);
-%name(ssl_get_alert_desc) extern char *SSL_alert_desc_string(int);
-%name(ssl_get_alert_desc_v) extern char *SSL_alert_desc_string_long(int);
+%name(ssl_get_state) extern const char *SSL_state_string(const SSL *);
+%name(ssl_get_state_v) extern const char *SSL_state_string_long(const SSL *);
+%name(ssl_get_alert_type) extern const char *SSL_alert_type_string(int);
+%name(ssl_get_alert_type_v) extern const char *SSL_alert_type_string_long(int);
+%name(ssl_get_alert_desc) extern const char *SSL_alert_desc_string(int);
+%name(ssl_get_alert_desc_v) extern const char *SSL_alert_desc_string_long(int);
%name(sslv2_method) extern SSL_METHOD *SSLv2_method(void);
%name(sslv3_method) extern SSL_METHOD *SSLv3_method(void);
m2crypto-0.09-mkreq.patch
(text/plain, 7.2 KB)
diff -ruN m2crypto-0.09-openssl0.9.7/M2Crypto/EVP.py m2crypto-0.09-mkreq/M2Crypto/EVP.py
--- m2crypto-0.09-openssl0.9.7/M2Crypto/EVP.py 2003-02-13 19:03:00.000000000 +1300
+++ m2crypto-0.09-mkreq/M2Crypto/EVP.py 2003-02-14 06:12:35.000000000 +1300
@@ -112,6 +112,12 @@
def final(self):
return m2.sign_final(self.ctx, self.pkey)
+ def assign_rsa(self, rsa):
+ ret = m2.pkey_assign_rsa(self.pkey, rsa.rsa)
+ if ret:
+ rsa._pyfree = 0
+ return ret
+
def load_key(file, callback=util.passphrase_callback):
bio = m2.bio_new_file(file, 'r')
if bio is None:
diff -ruN m2crypto-0.09-openssl0.9.7/M2Crypto/X509.py m2crypto-0.09-mkreq/M2Crypto/X509.py
--- m2crypto-0.09-openssl0.9.7/M2Crypto/X509.py 2003-02-13 19:03:00.000000000 +1300
+++ m2crypto-0.09-mkreq/M2Crypto/X509.py 2003-02-14 06:19:29.000000000 +1300
@@ -67,6 +67,13 @@
else:
raise AttributeError, (self, attr)
+ def __setattr__(self, attr, value):
+ if attr in self.nid.keys():
+ assert m2.x509_name_type_check(self.x509_name), "'x509_name' type error"
+ return m2.x509_name_set_by_nid(self.x509_name, self.nid[attr], value)
+ else:
+ self.__dict__[attr] = value
+
class X509:
@@ -221,6 +228,27 @@
m2.x509_req_print(buf.bio_ptr(), self.req)
return buf.read_all()
+ def as_pem(self):
+ buf=BIO.MemoryBuffer()
+ m2.x509_req_write_pem(buf.bio_ptr(), self.req)
+ return buf.read_all()
+
+ def save_pem(self, filename):
+ bio=BIO.openfile(filename, 'wb')
+ return m2.x509_req_write_pem(bio.bio_ptr(), self.req)
+
+ def set_pubkey(self, pkey):
+ return m2.x509_req_set_pubkey(self.req, pkey.pkey)
+
+ def get_subject(self):
+ return X509_Name(m2.x509_req_get_subject_name(self.req))
+
+ def sign(self, pkey, md):
+ mda = getattr(m2, md)
+ if not mda:
+ raise ValueError, ('unknown message digest', md)
+ return m2.x509_req_sign(self.req, pkey.pkey, mda())
+
def load_request(pemfile):
f=BIO.openfile(pemfile)
cptr=m2.x509_req_read_pem(f.bio_ptr())
diff -ruN m2crypto-0.09-openssl0.9.7/swig/_evp.i m2crypto-0.09-mkreq/swig/_evp.i
--- m2crypto-0.09-openssl0.9.7/swig/_evp.i 2003-02-14 05:29:29.000000000 +1300
+++ m2crypto-0.09-mkreq/swig/_evp.i 2003-02-14 05:32:24.000000000 +1300
@@ -46,16 +46,19 @@
%name(cast5_cbc) extern const EVP_CIPHER *EVP_cast5_cbc(void);
%name(cast5_cfb) extern const EVP_CIPHER *EVP_cast5_cfb(void);
%name(cast5_ofb) extern const EVP_CIPHER *EVP_cast5_ofb(void);
+/*
%name(rc5_ecb) extern const EVP_CIPHER *EVP_rc5_32_12_16_ecb(void);
%name(rc5_cbc) extern const EVP_CIPHER *EVP_rc5_32_12_16_cbc(void);
%name(rc5_cfb) extern const EVP_CIPHER *EVP_rc5_32_12_16_cfb(void);
%name(rc5_ofb) extern const EVP_CIPHER *EVP_rc5_32_12_16_ofb(void);
+*/
%name(rc4) extern const EVP_CIPHER *EVP_rc4(void);
%name(rc2_40_cbc) extern const EVP_CIPHER *EVP_rc2_40_cbc(void);
%name(pkey_new) extern EVP_PKEY *EVP_PKEY_new(void);
%name(pkey_free) extern void EVP_PKEY_free(EVP_PKEY *);
%name(sign_init) extern int EVP_SignInit(EVP_MD_CTX *, const EVP_MD *);
+%name(pkey_assign) extern int EVP_PKEY_assign(EVP_PKEY *pkey, int type, char *key);
%inline %{
#define PKCS5_SALT_LEN 8
@@ -491,5 +494,9 @@
Py_DECREF(pyfunc);
return pk;
}
+
+int pkey_assign_rsa(EVP_PKEY *pkey, RSA *rsa) {
+ return EVP_PKEY_assign_RSA(pkey, rsa);
+}
%}
diff -ruN m2crypto-0.09-openssl0.9.7/swig/_x509.i m2crypto-0.09-mkreq/swig/_x509.i
--- m2crypto-0.09-openssl0.9.7/swig/_x509.i 2003-02-13 19:03:00.000000000 +1300
+++ m2crypto-0.09-mkreq/swig/_x509.i 2003-02-13 21:13:40.000000000 +1300
@@ -12,6 +12,7 @@
%apply Pointer NONNULL { X509_REQ * };
%name(x509_free) extern void X509_free(X509 *);
+%name(x509_req_new) extern X509_REQ * X509_REQ_new();
%name(x509_req_free) extern void X509_REQ_free(X509_REQ *);
%name(x509_crl_free) extern void X509_CRL_free(X509_CRL *);
%name(x509_name_free) extern void X509_NAME_free(X509_NAME *);
@@ -27,6 +28,8 @@
%name(x509_get_verify_error) extern const char *X509_verify_cert_error_string(long);
+%name(x509_req_set_pubkey) extern int X509_REQ_set_pubkey(X509_REQ *, EVP_PKEY *);
+
%name(i2d_x509) extern int i2d_X509_bio(BIO *, X509 *);
%name(x509_store_new) extern X509_STORE *X509_STORE_new(void);
@@ -88,6 +91,10 @@
return PEM_read_bio_X509_REQ(bio, NULL, NULL, NULL);
}
+int x509_req_write_pem(BIO *bio, X509_REQ *x) {
+ return PEM_write_bio_X509_REQ(bio, x);
+}
+
X509_CRL *x509_crl_read_pem(BIO *bio) {
return PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL);
}
@@ -150,6 +157,11 @@
return ret;
}
+int x509_name_set_by_nid(X509_NAME *name, int nid, PyObject *obj) {
+ return X509_NAME_add_entry_by_NID(name, nid, MBSTRING_ASC, PyString_AsString(obj),
+ -1, -1, 0);
+}
+
/* sk_X509_new_null() is a macro returning "STACK_OF(X509) *". */
STACK *sk_x509_new_null(void) {
return (STACK *)sk_X509_new_null();
@@ -181,4 +193,12 @@
int x509_name_type_check(X509_NAME *name) {
return 1;
}
+
+X509_NAME *x509_req_get_subject_name(X509_REQ *x) {
+ return X509_REQ_get_subject_name(x);
+}
+
+int x509_req_sign(X509_REQ *x, EVP_PKEY *pkey, EVP_MD *md) {
+ return X509_REQ_sign(x, pkey, md);
+}
%}
diff -ruN m2crypto-0.09-openssl0.9.7/tests/alltests.py m2crypto-0.09-mkreq/tests/alltests.py
--- m2crypto-0.09-openssl0.9.7/tests/alltests.py 2003-02-13 19:03:00.000000000 +1300
+++ m2crypto-0.09-mkreq/tests/alltests.py 2003-02-14 06:33:07.000000000 +1300
@@ -12,7 +12,8 @@
'test_authcookie',
'test_dh',
'test_dsa',
- 'test_rsa']
+ 'test_rsa',
+ 'test_x509']
if os.name == 'posix':
modules_to_test.append('test_ssl')
elif os.name == 'nt':
diff -ruN m2crypto-0.09-openssl0.9.7/tests/test_x509.py m2crypto-0.09-mkreq/tests/test_x509.py
--- m2crypto-0.09-openssl0.9.7/tests/test_x509.py 1970-01-01 12:00:00.000000000 +1200
+++ m2crypto-0.09-mkreq/tests/test_x509.py 2003-02-14 18:50:53.000000000 +1300
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+
+"""Unit tests for M2Crypto.X509.
+
+Copyright (c) 2003 Ng Pheng Siong. All rights reserved."""
+
+RCS_id='$Id$'
+
+import unittest
+import os
+from M2Crypto import X509, EVP, RSA, Rand
+
+class X509TestCase(unittest.TestCase):
+
+ def callback(self, *args):
+ pass
+
+ def mkreq(self, bits, serial, days):
+ pk=EVP.PKey()
+ x=X509.Request()
+ rsa=RSA.gen_key(bits,65537,self.callback)
+ pk.assign_rsa(rsa)
+ rsa=None # should not be freed here
+ x.set_pubkey(pk)
+ name=x.get_subject()
+ name.C = "UK"
+ name.CN = "OpenSSL Group"
+ x.sign(pk,'md5')
+ return x, pk
+
+ def check_mkreq(self):
+ req, pk = self.mkreq(512, 0, 365)
+ req.save_pem('tmp_request.pem')
+ req2 = X509.load_request('tmp_request.pem')
+ os.remove('tmp_request.pem')
+ assert req.as_pem() == req2.as_pem()
+ assert req.as_text() == req2.as_text()
+
+def suite():
+ return unittest.makeSuite(X509TestCase, 'check')
+
+
+if __name__ == '__main__':
+ Rand.load_file('randpool.dat', -1)
+ unittest.TextTestRunner().run(suite())
+ Rand.save_file('randpool.dat')
signature.asc
(application/pgp-signature, 189 B)
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.0 (GNU/Linux) iD8DBQE+TIW9C4yI6AAOM8MRAla7AJ4zMxHDOiXWjC4s7B9UajCldrxW4QCfaoLY jZ+vbvv5GGsafNHAbGrjW+o= =tXYU -----END PGP SIGNATURE-----