Exemple #1
0
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)
Exemple #2
0
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)
Exemple #3
0
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
Exemple #4
0
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