def generateHSDesc(replica): """Generate a ``@type rendezvous-service-descriptor`` for an Hidden Service. .. todo:: Make generation of ``permanent_ids`` deal with HS "stealth" authorisation. .. todo:: Implement per-client ``session_keys`` and ``descriptor_cookies``, see rend-spec.txt §2.1. :param int replica: The ``replica`` number for this particular descriptor. This influences the ``secret-id-part`` of the descriptor (see :func:`~leekspin.rendezvous.calculateSecretIDPart`). :rtype: str :returns: A ``@type rendezvous-service-descriptor`` as a string. """ import time vers = torversions.getRandomVersion() versionsLine = rendezvous.generateVersionLine(vers) protocolVersionsLine = rendezvous.generateProtocolVersionsLine(vers) (secretPermanentKey, publicPermanentKey, permanentKeyLine) = rendezvous.generatePermanentKey() (secretSigningKey, publicSigningKey, signingKeyLine) = crypto.generateSigningKey() # TODO: Make generation of permanent_ids deal with HS "stealth" authorisation. permanentID = rendezvous.generatePermanentID(publicPermanentKey) # TODO: Implement per-client session-keys / descriptor cookies, see # rend-spec.txt §2.1. descCookie = rendezvous.createDescriptorCookie() descCookieB64 = base64.b64encode(descCookie)#.strip("=") # see rendclient.c rend_parse_service_authorization()↑↑↑ logging.info(("# Generated HS .onion address: %s\n" "# Generated HS descriptor cookie: %s") % (permanentID.encode("hex") + ".onion", descCookieB64)) currentTime = int(time.time()) publicationTimeLine = rendezvous.generatePublicationTimeLine(currentTime) (secretIDPart, secretIDLine) = rendezvous.calculateSecretIDPart(permanentID, currentTime, descCookieB64, replica) introductionPoints = rendezvous.generateIntroPoints(descCookieB64) rendServiceLine = rendezvous.generateRendServiceLine(permanentID, secretIDPart, replica) d = [] d.append(rendServiceLine) d.append(versionsLine) d.append(permanentKeyLine) d.append(secretIDLine) d.append(publicationTimeLine) d.append(protocolVersionsLine) d.append(introductionPoints) d.append(const.TOKEN_HS_SIGNATURE) document = "\r\n".join(d) + "\r\n" (_, _, documentDigestPKCS1) = crypto.digestDescriptorContent(document) descriptor = crypto.signDescriptorContent(document, secretSigningKey, token=const.TOKEN_HS_SIGNATURE) # "router-signature" is for relay/bridge descriptor signatures; we have to # replace it with just "signature": descriptor = descriptor.replace("router-signature", "signature") logging.info("%s\n" % descriptor) return descriptor
def generateDescriptors(bridge=True, withoutTAP=False, withoutNTOR=False): """Create keys, certs, signatures, documents and descriptors for an OR. :param bool bridge: If ``True``, generate Bridge descriptors; otherwise, generate Relay descriptors. :param bool withoutTAP: If ``True``, generate descriptors without support for the TAP handshake, e.g. without RSA keys. :param bool withoutTAP: If ``True``, generate descriptors without support for the ntor handshake, e.g. without Ed25519 keys. :returns: A 3-tuple of strings: - a ``@type [bridge-]extra-info`` descriptor, - a ``@type [bridge-]server-descriptor``, and - a ``@type network-status`` document for a mock Tor relay/bridge. """ ipv4 = util.randomIPv4() ipv6 = util.randomIPv6() port = util.randomPort() nick = nicknames.generateNickname() vers = torversions.getRandomVersion() uptime = int(random.randint(1800, 63072000)) bandwidth = server.makeBandwidthLine() timestamp = util.makeTimeStamp(variation=True, period=36) protocols = server.makeProtocolsLine(vers) if withoutTAP: (secretOnionKey, publicOnionKey, onionKeyLine) = (None, None, None) else: (secretOnionKey, publicOnionKey, onionKeyLine) = crypto.generateOnionKey() (secretSigningKey, publicSigningKey, signingKeyLine) = crypto.generateSigningKey() secretNTORKey = None publicNTORKey = None if not withoutNTOR and nacl: try: secretNTORKey = ntor.createNTORSecretKey() publicNTORKey = ntor.getNTORPublicKey(secretNTORKey) except ntor.NTORKeyCreationError as error: secretNTORKey = None publicNTORKey = None (fingerprintSpacey, fingerprintBinary) = crypto.getFingerprint(publicSigningKey) fingerprintSmooshed = crypto.convertToSmooshedFingerprint(fingerprintSpacey) extrainfoDoc = extrainfo.generateExtraInfo(nick, fingerprintSmooshed, timestamp, ipv4, port, bridge=bridge) (extrainfoDigestBinary, extrainfoDigest, extrainfoDigestPKCS1) = crypto.digestDescriptorContent(extrainfoDoc) extrainfoDesc = crypto.signDescriptorContent(extrainfoDoc, secretSigningKey, digest=extrainfoDigestPKCS1) serverDoc = server.generateServerDescriptor(nick, fingerprintSpacey, timestamp, ipv4, ipv6, port, vers, protocols, uptime, bandwidth, extrainfoDigest, onionKeyLine, signingKeyLine, publicNTORKey, bridge=bridge) (serverDigestBinary, serverDigest, serverDigestPKCS1) = crypto.digestDescriptorContent(serverDoc) if bridge: serverDoc = b'@purpose bridge\n' + serverDoc serverDesc = crypto.signDescriptorContent(serverDoc, secretSigningKey, digest=serverDigestPKCS1) netstatusDesc = netstatus.generateBridgeNetstatus(nick, fingerprintBinary, serverDigestBinary, timestamp, ipv4, port, ipv6=ipv6, bandwidth_line=bandwidth) return (extrainfoDesc, serverDesc, netstatusDesc)
def generateDescriptors(): """Create keys, certs, signatures, documents and descriptors for an OR. :returns: A 3-tuple of strings: - a ``@type [bridge-]extra-info`` descriptor, - a ``@type [bridge-]server-descriptor``, and - a ``@type network-status`` document for a mock Tor relay/bridge. """ ipv4 = util.randomIPv4() ipv6 = util.randomIPv6() port = util.randomPort() nick = nicknames.generateNickname() vers = torversions.getRandomVersion() uptime = int(random.randint(1800, 63072000)) bandwidth = server.makeBandwidthLine() timestamp = util.makeTimeStamp(variation=True, period=36) protocols = server.makeProtocolsLine(vers) SIDSKey, SIDPCert, (onionkey, signingkey) = crypto.makeOnionKeys() idkeyPrivate = tls.getPrivateKey(SIDSKey) idkeyDigest = hashlib.sha1(idkeyPrivate).digest() idkeyPublic = OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_ASN1, SIDPCert.get_pubkey()) idkeyPublic = re.sub(const.OPENSSL_BEGIN_KEY, '', idkeyPublic) idkeyPublic = re.sub(const.OPENSSL_END_KEY, '', idkeyPublic) idkeyPublic = idkeyPublic.strip() identDigest = hashlib.sha1(idkeyPublic).digest() fingerprint = hashlib.sha1(idkeyPublic).hexdigest().upper() fpr = crypto.convertToSpaceyFingerprint(fingerprint) extrainfoDoc = extrainfo.generateExtraInfo(nick, fingerprint, timestamp, ipv4, port) extrainfoDigest = hashlib.sha1(extrainfoDoc).digest() extrainfoHexdigest = hashlib.sha1(extrainfoDoc).hexdigest().upper() extrainfoSig = crypto.signDescriptorDigest(SIDSKey, extrainfoDigest) extrainfoDesc = extrainfoDoc + extrainfoSig serverDoc = [] serverDoc.append("@purpose bridge") serverDoc.append("router %s %s %s 0 0" % (nick, ipv4, port)) serverDoc.append("or-address [%s]:%s" % (ipv6, port)) serverDoc.append("platform Tor %s on Linux" % vers) serverDoc.append("%s\npublished %s" % (protocols, timestamp)) serverDoc.append("%s" % server.makeFingerprintLine(fingerprint, vers)) serverDoc.append("uptime %s\n%s" % (uptime, bandwidth)) serverDoc.append("%s" % server.makeExtraInfoDigestLine(extrainfoHexdigest, vers)) serverDoc.append("%s%s%s" % (onionkey, signingkey, server.makeHSDirLine(vers))) serverDoc.append("contact Somebody <*****@*****.**>") if nacl is not None: ntorkey = ntor.getNTORPublicKey() if ntorkey is not None: serverDoc.append("ntor-onion-key %s" % ntorkey) serverDoc.append("reject *:*\nrouter-signature\n") serverDesc = '\n'.join(serverDoc) serverDescDigest = hashlib.sha1(serverDesc).digest() netstatusDesc = netstatus.generateNetstatus(nick, identDigest, serverDescDigest, timestamp, ipv4, port, ipv6=ipv6, bandwidth_line=bandwidth) serverDesc += crypto.signDescriptorDigest(SIDSKey, serverDescDigest) return extrainfoDesc, serverDesc, netstatusDesc