def answer_dns_challenge(client, domain, challenge): """ Compute the required answer and set it in the DNS record for the domain. """ authorization = "{}.{}".format( base64.urlsafe_b64encode( challenge.get("token")).decode("ascii").replace("=", ""), base64.urlsafe_b64encode( client.key.thumbprint()).decode("ascii").replace("=", "")) dns_response = base64.urlsafe_b64encode( hashlib.sha256( authorization.encode()).digest()).decode("ascii").replace("=", "") # Let's update the DNS on our R53 account r53 = route53.connect_to_region(exec_region) zone = r53.get_zone(domain['r53_zone']) if zone == None: LOG.error("Cannot find R53 zone {}, are you controling it ?".format( domain['r53_zone'])) exit(1) acme_domain = "_acme-challenge.{}".format(domain['name']) record = zone.find_records(name=acme_domain, type="TXT") if record: delete_status = zone.delete_record(record) add_status = zone.add_record("TXT", acme_domain, '"' + dns_response + '"') dns_updated = wait_until_sync(add_status) if dns_updated == False: LOG.error( "We updated R53 but the servers didn't sync within 10 seconds. Bailing out." ) exit(1) ## Now, let's tell the ACME server that we are ready challenge_response = challenges.DNS01Response( key_authorization=authorization) challenge_resource = client.answer_challenge(challenge, challenge_response)
def wildcard_request(cn, account): def dns_check_ns1(): recieved_data_dup = [] recieved_data = [] ns1_resolver = dns.resolver.Resolver() #ns1_resolver.nameservers = ['130.193.8.82','2a03:b780::1:1'] ns1_resolver.nameservers = ['173.245.58.51'] for data in validation_data: domainname = data[1] #challenge = data[0] answers = ns1_resolver.query(domainname, 'txt') for rdata in answers: recieved_data_dup.append( [str(rdata).replace('"', ''), domainname]) #Deduplication of ns records (in case of more cnames) for i in recieved_data_dup: if i not in recieved_data: recieved_data.append(i) # print sorted(recieved_data) # print sorted(validation_data) if sorted(validation_data) == sorted(recieved_data): return True else: return False #Check if CN is valid domain domain_regex = re.compile( "^([a-zA-Z0-9]([\-a-zA-Z0-9]{0,61}[a-zA-Z0-9])?\.)*([a-zA-Z0-9]([\-a-zA-Z0-9]{0,61}[a-zA-Z0-9])+\.)([a-zA-Z0-9]+([\-a-zA-Z0-9]{0,61}[a-zA-Z])+)$" ) if not domain_regex.match(cn): print 'First argument is not valid CN' sys.exit(1) #Check if registrar exists if account not in os.listdir(REG_DIRECTORY): print "This account does not exists, register it first with new_account.py" sys.exit(1) #Load files from disk with open(REG_DIRECTORY + "/" + account + "/private.key", "rb") as key_file: privkey = serialization.load_pem_private_key(key_file.read(), password=None, backend=default_backend()) with open(REG_DIRECTORY + "/" + account + "/reguri.txt", "r") as reguri_file: reg_uri = reguri_file.read() #Compose regr key = jose.JWKRSA(key=privkey) regr = messages.RegistrationResource( body=messages.Registration(key=key.public_key()), uri=reg_uri) #Init ACME net = ClientNetwork(key) directory = net.get(DIRECTORY_URL).json() acme = client.ClientV2(directory, net) #Check if registration is valid if acme.query_registration(regr).body.status == u'valid': print "Registration valid" else: print "Registration invalid" sys.exit(1) #Generate private key for certificate pkey = OpenSSL.crypto.PKey() pkey.generate_key(OpenSSL.crypto.TYPE_RSA, BITS) #Serialize key for output pkey_printable = OpenSSL.crypto.dump_privatekey( OpenSSL.crypto.FILETYPE_PEM, pkey, cipher=None, passphrase=None) #Compose request for acme req = crypto_util.make_csr( OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, pkey), [cn, '*.' + cn]) #begin order orderr = acme.new_order(req) validation_data = [] for authr in orderr.authorizations: for chalr in authr.body.challenges: if type(chalr.chall) == type(challenges.DNS01()): validation_data.append([ str(chalr.chall.validation(key)), chalr.chall.validation_domain_name(cn) ]) #print validation_data #Now, call DNS writing function to apply challenges dns_apply(cn, validation_data) #Check if DNS is valid on our server sys.stdin.readline() #DEBUG: wait for manual DNS input limiter = 2 while not dns_check_ns1(): if limiter != 0: print "DNS records are not correct, trying again in few seconds" limiter = limiter - 1 time.sleep(5) else: print "DNS are not correct even after several tries. Aborting" sys.exit(1) for authr in orderr.authorizations: for chalr in authr.body.challenges: if type(chalr.chall) == type(challenges.DNS01()): try: acme.answer_challenge(chalr, challenges.DNS01Response()) except: print chalr.chall.encode( 'token' ) + " already answered (challenge failed, you have to generate new one)" #After filling DNS and waiting for propagation, finalize order try: res = acme.poll_and_finalize(orderr) finally: dns_remove(cn) #logging.info(res) cert = x509.load_pem_x509_certificate(str(res.fullchain_pem), default_backend()) output_data = { 'wildcard': { 'cn': cn, 'private_key': str(pkey_printable), 'certificate': str(res.fullchain_pem), 'expiration': cert.not_valid_after.strftime( "%x %X" ) #Locale-specific time+date representation. Edit to your need } } print json.dumps(output_data)
def answer_dns_challenge(conf, client, domain, challenge): """ Compute the required answer and set it in the DNS record for the domain. """ zone_id = conf['r53_zone_id'] account_key = client.net.key authorization = "{}.{}".format( base64.urlsafe_b64encode( challenge.get("token")).decode("ascii").replace("=", ""), base64.urlsafe_b64encode( account_key.thumbprint()).decode("ascii").replace("=", "")) dns_response = base64.urlsafe_b64encode( hashlib.sha256( authorization.encode()).digest()).decode("ascii").replace("=", "") LOG.info("authorization ='{0}' dns_response= '{1}' for Id".format( authorization, dns_response)) #domain_name = '.'.join(domain['name'].split('.')[1:]) domain_name = domain['name'].replace( '*.', '') if domain['name'].startswith('*.') else domain['name'] acme_domain = "_acme-challenge.%s.%s" % (domain_name, conf['r53_zone']) res = reset_route53_letsencrypt_record(zone_id, acme_domain) if res is None: LOG.error( "An error occured while trying to remove a " "previous resource record. Skipping domain %s", domain_name) return None add_status = create_route53_letsencrypt_record(zone_id, acme_domain, '"' + dns_response + '"') if add_status is None: LOG.error( "An error occured while creating the dns record. " "Skipping domain %s", domain_name) return None add_status = wait_letsencrypt_record_insync(add_status) if add_status is None: LOG.error( "Cannot determine if the dns record has been correctly created. " "Skipping domain {0}".format(domain_name)) return None if add_status is False: LOG.error( "We updated R53 but the servers didn't sync within 60 seconds. " "Skipping domain {0}".format(domain_name)) return None if add_status is not True: LOG.error( "An unexpected result code has been returned. Please report this bug. " "Skipping domain {0}".format(domain_name)) LOG.error("add_status={0}".format(add_status)) return None challenge_response = challenges.DNS01Response( key_authorization=authorization) challenge_resource = client.answer_challenge(challenge, challenge_response) if challenge_resource.body.error is not None: return False return True
def answer_dns_challenge(conf, client, domain, challenge): """ Compute the required answer and set it in the DNS record for the domain. """ authorization = "{}.{}".format( base64.urlsafe_b64encode( challenge.get("token")).decode("ascii").replace("=", ""), base64.urlsafe_b64encode( client.key.thumbprint()).decode("ascii").replace("=", "")) dns_response = base64.urlsafe_b64encode( hashlib.sha256( authorization.encode()).digest()).decode("ascii").replace("=", "") # Let's update the DNS on our R53 account zone_id = get_route53_zone_id(conf, domain['r53_zone']) if zone_id == None: LOG.error("Cannot determine zone id for zone '{0}'".format( domain['r53_zone'])) return None LOG.info("Domain '{0}' has '{1}' for Id".format(domain['r53_zone'], zone_id)) zone_id = get_route53_zone_id(conf, domain['r53_zone']) if zone_id == None: LOG.error("Cannot find R53 zone {}, are you controling it ?".format( domain['r53_zone'])) return None acme_domain = "_acme-challenge.{}".format(domain['name']) res = reset_route53_letsencrypt_record(conf, zone_id, domain['name'], acme_domain) if res == None: LOG.error( "An error occured while trying to remove a previous resource record. Skipping domain {0}" .format(domain['name'])) return None add_status = create_route53_letsencrypt_record(conf, zone_id, domain['name'], acme_domain, 'TXT', '"' + dns_response + '"') if add_status == None: LOG.error( "An error occured while creating the dns record. Skipping domain {0}" .format(domain['name'])) return None add_status = wait_letsencrypt_record_insync(conf, add_status) if add_status == None: LOG.error( "Cannot determine if the dns record has been correctly created. Skipping domain {0}" .format(domain['name'])) return None if add_status == False: LOG.error( "We updated R53 but the servers didn't sync within 60 seconds. Skipping domain {0}" .format(domain['name'])) return None if add_status is not True: LOG.error( "An unexpected result code has been returned. Please report this bug. Skipping domain {0}" .format(domain['name'])) LOG.error("add_status={0}".format(add_status)) return None ## Now, let's tell the ACME server that we are ready challenge_response = challenges.DNS01Response( key_authorization=authorization) challenge_resource = client.answer_challenge(challenge, challenge_response) if challenge_resource.body.error != None: return False return True