diff --git a/CHANGELOG.md b/CHANGELOG.md index 623652d..3cddb2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Support for storing multiple GMSAs secrets in a single keytab file (#5) +- Print Kerberos error names (#7) ## [0.1.0] - 2023-06-05 diff --git a/gmsad/salt.py b/gmsad/salt.py index beee8f0..f3ab23f 100644 --- a/gmsad/salt.py +++ b/gmsad/salt.py @@ -23,6 +23,7 @@ import random import socket from typing import Any as AnyType +from enum import IntEnum from asn1crypto.core import Sequence, SequenceOf, Integer, BitString, OctetString, GeneralString, \ GeneralizedTime, Any @@ -52,6 +53,77 @@ KERBEROS_PORT = 88 +# From RFC 4120 section 7.5.9 +class KRBErrorCode(IntEnum): + KDC_ERR_NONE = 0 + KDC_ERR_NAME_EXP = 1 + KDC_ERR_SERVICE_EXP = 2 + KDC_ERR_BAD_PVNO = 3 + KDC_ERR_C_OLD_MAST_KVNO = 4 + KDC_ERR_S_OLD_MAST_KVNO = 5 + KDC_ERR_C_PRINCIPAL_UNKNOWN = 6 + KDC_ERR_S_PRINCIPAL_UNKNOWN = 7 + KDC_ERR_PRINCIPAL_NOT_UNIQUE = 8 + KDC_ERR_NULL_KEY = 9 + KDC_ERR_CANNOT_POSTDATE = 10 + KDC_ERR_NEVER_VALID = 11 + KDC_ERR_POLICY = 12 + KDC_ERR_BADOPTION = 13 + KDC_ERR_ETYPE_NOSUPP = 14 + KDC_ERR_SUMTYPE_NOSUPP = 15 + KDC_ERR_PADATA_TYPE_NOSUPP = 16 + KDC_ERR_TRTYPE_NOSUPP = 17 + KDC_ERR_CLIENT_REVOKED = 18 + KDC_ERR_SERVICE_REVOKED = 19 + KDC_ERR_TGT_REVOKED = 20 + KDC_ERR_CLIENT_NOTYET = 21 + KDC_ERR_SERVICE_NOTYET = 22 + KDC_ERR_KEY_EXPIRED = 23 + KDC_ERR_PREAUTH_FAILED = 24 + KDC_ERR_PREAUTH_REQUIRED = 25 + KDC_ERR_SERVER_NOMATCH = 26 + KDC_ERR_MUST_USE_USER2USER = 27 + KDC_ERR_PATH_NOT_ACCEPTED = 28 + KDC_ERR_SVC_UNAVAILABLE = 29 + KRB_AP_ERR_BAD_INTEGRITY = 31 + KRB_AP_ERR_TKT_EXPIRED = 32 + KRB_AP_ERR_TKT_NYV = 33 + KRB_AP_ERR_REPEAT = 34 + KRB_AP_ERR_NOT_US = 35 + KRB_AP_ERR_BADMATCH = 36 + KRB_AP_ERR_SKEW = 37 + KRB_AP_ERR_BADADDR = 38 + KRB_AP_ERR_BADVERSION = 39 + KRB_AP_ERR_MSG_TYPE = 40 + KRB_AP_ERR_MODIFIED = 41 + KRB_AP_ERR_BADORDER = 42 + KRB_AP_ERR_BADKEYVER = 44 + KRB_AP_ERR_NOKEY = 45 + KRB_AP_ERR_MUT_FAIL = 46 + KRB_AP_ERR_BADDIRECTION = 47 + KRB_AP_ERR_METHOD = 48 + KRB_AP_ERR_BADSEQ = 49 + KRB_AP_ERR_INAPP_CKSUM = 50 + KRB_AP_PATH_NOT_ACCEPTED = 51 + KRB_ERR_RESPONSE_TOO_BIG = 52 + KRB_ERR_GENERIC = 60 + KRB_ERR_FIELD_TOOLONG = 61 + KDC_ERROR_CLIENT_NOT_TRUSTED = 62 + KDC_ERROR_KDC_NOT_TRUSTED = 63 + KDC_ERROR_INVALID_SIG = 64 + KDC_ERR_KEY_TOO_WEAK = 65 + KDC_ERR_CERTIFICATE_MISMATCH = 66 + KRB_AP_ERR_NO_TGT = 67 + KDC_ERR_WRONG_REALM = 68 + KRB_AP_ERR_USER_TO_USER_REQUIRED = 69 + KDC_ERR_CANT_VERIFY_CERTIFICATE = 70 + KDC_ERR_INVALID_CERTIFICATE = 71 + KDC_ERR_REVOKED_CERTIFICATE = 72 + KDC_ERR_REVOCATION_STATUS_UNKNOWN = 73 + KDC_ERR_REVOCATION_STATUS_UNAVAILABLE = 74 + KDC_ERR_CLIENT_NAME_MISMATCH = 75 + KDC_ERR_KDC_NAME_MISMATCH = 76 + class EncryptedData(Sequence): _fields = [ ('etype', Integer, {'explicit': 0}), @@ -274,7 +346,7 @@ def get_salt_from_rep(kdc_rep: bytes) -> str: if tag == KRB_ERROR_TAG_NUMBER: err = KRB_ERROR.load(kdc_rep) error_code = err['error-code'].native - if error_code == KDC_ERR_PREAUTH_REQUIRED: + if error_code == KRBErrorCode.KDC_ERR_PREAUTH_REQUIRED: for padata in PA_DATA_SEQUENCE_OF.load(err['e-data'].native): if padata['padata-type'].native == PA_ETYPE_INFO2: etype = ETYPE_INFO2() @@ -282,6 +354,8 @@ def get_salt_from_rep(kdc_rep: bytes) -> str: if pa_etype_info2_value['etype'].native == AES256_CTS_HMAC_SHA1h96_ENC_TYPE: # XXX: Adding str just for mypy return str(pa_etype_info2_value['salt'].native) + else: + raise Exception(f"Could not retrieve salt from AS_REP, got Kerberos error {KRBErrorCode(error_code).name} ({error_code})") elif tag == AS_REP_TAG_NUMBER: # In this case the gMSA has the DONT_REQUIRE_PREAUTH flag in its # userAccountControl attribute