[Git][reproducible-builds/reproducible-misc][master] 2 commits: Add certs.py to handle the debsso certs
Mattia Rizzolo
gitlab at salsa.debian.org
Wed May 16 14:44:23 CEST 2018
Mattia Rizzolo pushed to branch master at Reproducible Builds / reproducible-misc
Commits:
102df949 by Mattia Rizzolo at 2018-05-16T13:37:55+02:00
Add certs.py to handle the debsso certs
Originally from https://github.com/spanezz/debsso-client/blob/master/debssolib/certs.py
Signed-off-by: Mattia Rizzolo <mattia at debian.org>
- - - - -
86ded378 by Mattia Rizzolo at 2018-05-16T14:41:45+02:00
New script: `schedule` to request scheduling of builds (still WIP and not functional)
Signed-off-by: Mattia Rizzolo <mattia at debian.org>
- - - - -
2 changed files:
- + rblib/certs.py
- + schedule
Changes:
=====================================
rblib/certs.py
=====================================
--- /dev/null
+++ b/rblib/certs.py
@@ -0,0 +1,124 @@
+# Copyright: 2016-2017 Enrico Zini <enrico at debian.org>
+# License: GPL-2
+
+import os
+import subprocess
+import contextlib
+import requests
+import tempfile
+
+class Browser:
+ def __init__(self):
+ self.dbname = "sql:" + os.path.expanduser("~/.pki/nssdb")
+
+ def run_certutil(self, args, input=None):
+ cmd = ["certutil", "-d", self.dbname]
+ cmd.extend(args)
+ output = subprocess.check_output(cmd, universal_newlines=True, input=input)
+ return output
+
+ def run_pk12util(self, args, input=None):
+ cmd = ["pk12util", "-d", self.dbname]
+ cmd.extend(args)
+ output = subprocess.check_output(cmd, universal_newlines=False, input=input)
+ return output
+
+ def get_key_nicks(self):
+ output = self.run_certutil(["-L"])
+ payload = output.split("\n\n")[1]
+ for line in payload.splitlines():
+ nick, flags = line.rsplit(None, 1)
+ yield nick, flags
+
+ def get_sso_cert_nickname(self):
+ debemail = os.environ.get("DEBEMAIL", None)
+ if debemail is None: raise RuntimeError("$DEBEMAIL is not set")
+ for nick, flags in self.get_key_nicks():
+ if flags != "u,u,u": continue
+ if not nick.startswith(debemail): continue
+ if not "SSO" in nick: continue
+ return nick
+
+ def get_key_pkcs12(self, nick):
+ """
+ Read the certificate and key for the slot with the given nick and
+ return them in a single pkcs12 blob.
+ """
+ return self.run_pk12util(["-n", nick, "-o", "/dev/stdout", "-W", ""])
+
+
+def pkcs12_to_pem(pkcs12):
+ """
+ Return PEM-encoded certificate and key from their pkcs12 version
+ """
+ import OpenSSL.crypto
+ from OpenSSL.crypto import FILETYPE_PEM
+ p = OpenSSL.crypto.load_pkcs12(pkcs12, "")
+ return Certs(
+ pem_crt=OpenSSL.crypto.dump_certificate(FILETYPE_PEM, p.get_certificate()),
+ pem_key=OpenSSL.crypto.dump_privatekey(FILETYPE_PEM, p.get_privatekey()),
+ )
+ #pem_cert = subprocess.check_output(["openssl", "pkcs12", "-nodes", "-passin", "pass:", "-clcerts", "-nokeys"],
+ # input=pkcs12, stderr=open("/dev/null", "wb"))
+ #pem_key = subprocess.check_output(["openssl", "pkcs12", "-nodes", "-passin", "pass:", "-nocerts"],
+ # input=pkcs12, stderr=open("/dev/null", "wb"))
+ #return pem_cert, pem_key
+
+
+class Certfiles:
+ """
+ Manage certificate files stored in a directory
+ """
+ def __init__(self, dir, basename="sso"):
+ self.dir = dir
+ self.crt_pathname = os.path.join(dir, basename + ".crt")
+ self.key_pathname = os.path.join(dir, basename + ".key")
+
+ def write(self, certs):
+ with open(self.crt_pathname, "wb") as fd:
+ os.chmod(fd.fileno(), 0o400)
+ fd.write(certs.pem_crt)
+
+ with open(self.key_pathname, "wb") as fd:
+ os.chmod(fd.fileno(), 0o400)
+ fd.write(certs.pem_key)
+
+
+class Certs:
+ """
+ OpenSSL client certificate information, as a key and a certificate,
+ PEM-encoded
+ """
+ def __init__(self, pem_crt, pem_key):
+ self.pem_crt = pem_crt
+ self.pem_key = pem_key
+
+ @contextlib.contextmanager
+ def tempfiles(self):
+ with tempfile.TemporaryDirectory() as tmpdir:
+ files = Certfiles(tmpdir)
+ files.write(self)
+ yield files
+
+ @contextlib.contextmanager
+ def requests(self):
+ with self.tempfiles() as files:
+ with requests.Session() as session:
+ session.cert = (files.crt_pathname, files.key_pathname)
+ yield session
+
+ @classmethod
+ def from_browser(cls):
+ """
+ Return PEM-encoded (certificate, key) extracted from libnss3 key
+ storage used by common web browsers.
+ """
+ # Try to get SSO keys out of the browser and connect to nm.debian.org with
+ # them.
+ # Requires $DEBEMAIL to be set.
+ # Requires libnss3-tools, python3-openssl
+ # Tested with chromium.
+ browser = Browser()
+ nick = browser.get_sso_cert_nickname()
+ pkcs12 = browser.get_key_pkcs12(nick)
+ return pkcs12_to_pem(pkcs12)
=====================================
schedule
=====================================
--- /dev/null
+++ b/schedule
@@ -0,0 +1,59 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+# clean-notes: sort and clean the notes stored in notes.git
+# Copyright © 2018 Mattia Rizzolo <mattia at debian.org>
+# Licensed under WTFPL — http://www.wtfpl.net/txt/copying/
+
+import argparse
+from requests import codes as retcodes
+
+from rblib.certs import Certs
+
+
+def whoami():
+ '''
+ debugging function: check whether auth succeed
+ '''
+ certs = Certs.from_browser()
+ with certs.requests() as req:
+ res = req.get("https://nm.debian.org/api/whoami")
+ print(res.text)
+
+
+def send_req(args):
+ certs = Certs.from_browser()
+ with certs.requests() as req:
+ res = req.get("https://tests.reproducible-builds.org/cgi-bin/schedule")
+ ret = res.status_code
+ if ret == retcodes.ok:
+ print('Scheduling successful!')
+ if args.debug: print(res.text)
+ elif ret == retcodes.bad:
+ print('Validation error!')
+ print(res.headers['X-Error-Message'])
+ if args.debug: print(res.text)
+ elif ret == 520:
+ print('Unknown error while scheduling, check the output below')
+ print(res.text)
+ else:
+ raise ValueError('Unhandled status code {}'.format(ret))
+
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ '--check',
+ help='check whether your client cert is ok',
+ action='store_true',
+ )
+ parser.add_argument(
+ '-d', '--debug',
+ help='dump the text from the scheduler also when otherwise not needed.',
+ action='store_true',
+ )
+ args, remote_args = parser.parse_known_args()
+ if args.check:
+ whoami()
+ else:
+ send_req(args)
View it on GitLab: https://salsa.debian.org/reproducible-builds/reproducible-misc/compare/7b30e845719c8a21b1a75068d69ee817340c03ce...86ded37804540b905f5d2bbb13f606a8bd025693
---
View it on GitLab: https://salsa.debian.org/reproducible-builds/reproducible-misc/compare/7b30e845719c8a21b1a75068d69ee817340c03ce...86ded37804540b905f5d2bbb13f606a8bd025693
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.reproducible-builds.org/pipermail/rb-commits/attachments/20180516/6135f960/attachment.html>
More information about the rb-commits
mailing list